ProHoster > Blogi > antaminen > Tietojen palauttaminen XtraDB-taulukoista ilman rakennetiedostoa käyttämällä ibd-tiedoston tavu-tavu-analyysiä
Tietojen palauttaminen XtraDB-taulukoista ilman rakennetiedostoa käyttämällä ibd-tiedoston tavu-tavu-analyysiä
esihistoria
Kävi niin, että palvelimeen hyökkäsi lunnasohjelmavirus, joka "onnen sattuman" johdosta jätti osittain .ibd-tiedostot (innodb-taulukoiden raakadatatiedostot) koskematta, mutta samalla salasi .fpm-tiedostot kokonaan ( rakennetiedostot). Tässä tapauksessa .idb voidaan jakaa seuraavasti:
voidaan palauttaa vakiotyökalujen ja oppaiden avulla. Tällaisissa tapauksissa on olemassa erinomainen tulla;
osittain salatut taulukot. Useimmiten nämä ovat suuria taulukoita, joille (ymmärtääkseni) hyökkääjillä ei ollut tarpeeksi RAM-muistia täydelliseen salaukseen;
No, täysin salatut taulukot, joita ei voida palauttaa.
Oli mahdollista määrittää, mihin vaihtoehtoon taulukot kuuluvat, avaamalla se missä tahansa tekstieditorissa halutulla koodauksella (minun tapauksessani se on UTF8) ja yksinkertaisesti katsomalla tiedostoa tekstikenttien esiintymisen varalta, esimerkiksi:
Myös tiedoston alussa voi havaita suuren määrän 0 tavua ja lohkosalausalgoritmia käyttävät virukset (yleisin) vaikuttavat yleensä niihinkin.
Minun tapauksessani hyökkääjät jättivät 4-tavuisen merkkijonon (1, 0, 0, 0) jokaisen salatun tiedoston loppuun, mikä yksinkertaisti tehtävää. Saastumattomien tiedostojen etsimiseen komentosarja riitti:
def opened(path):
files = os.listdir(path)
for f in files:
if os.path.isfile(path + f):
yield path + f
for full_path in opened("C:somepath"):
file = open(full_path, "rb")
last_string = ""
for line in file:
last_string = line
file.close()
if (last_string[len(last_string) -4:len(last_string)]) != (1, 0, 0, 0):
print(full_path)
Näin ollen kävi ilmi, että löydettiin ensimmäiseen tyyppiin kuuluvia tiedostoja. Toinen sisältää paljon manuaalista työtä, mutta se, mitä löydettiin, oli jo tarpeeksi. Kaikki olisi hyvin, mutta sinun on tiedettävä täysin tarkka rakenne ja (tietysti) tapahtui tapaus, että minun piti työskennellä usein vaihtuvan pöydän kanssa. Kukaan ei muistanut, onko kentän tyyppiä muutettu vai lisätty uusi sarake.
Valitettavasti Wilds City ei voinut auttaa tällaisessa tapauksessa, minkä vuoksi tämä artikkeli kirjoitetaan.
Lähempänä asiaa
On olemassa kolmen kuukauden takaisen taulukon rakenne, joka ei ole sama kuin nykyinen (mahdollisesti yksi kenttä ja mahdollisesti useampi). Taulukon rakenne:
CREATE TABLE `table_1` (
`id` INT (11),
`date` DATETIME ,
`description` TEXT ,
`id_point` INT (11),
`id_user` INT (11),
`date_start` DATETIME ,
`date_finish` DATETIME ,
`photo` INT (1),
`id_client` INT (11),
`status` INT (1),
`lead__time` TIME ,
`sendstatus` TINYINT (4)
);
tässä tapauksessa sinun on purettava:
id_point int(11);
id_user int(11);
date_start TREFFIAIKA;
date_finish TREFFIAIKA.
Palautukseen käytetään .ibd-tiedoston tavukohtaista analyysiä, jonka jälkeen tiedostot muunnetaan luettavampaan muotoon. Koska tarvitsemamme löytämiseksi tarvitsemme vain analysoida tietotyyppejä, kuten int ja datatime, artikkelissa kuvataan vain ne, mutta joskus viitataan myös muihin tietotyyppeihin, joista voi olla apua muissa vastaavissa tapahtumissa.
1-ongelma: kentillä tyypeillä DATETIME ja TEXT oli NULL-arvot, ja ne yksinkertaisesti ohitetaan tiedostossa, tämän vuoksi minun tapauksessani ei ollut mahdollista määrittää palautettavaa rakennetta. Uusissa sarakkeissa oletusarvo oli nolla, ja osa tapahtumasta saattoi menettää asetuksen innodb_flush_log_at_trx_commit = 0 vuoksi, joten rakenteen määrittämiseen joutuisi käyttämään lisäaikaa.
2-ongelma: on otettava huomioon, että DELETE-toiminnolla poistetut rivit ovat kaikki ibd-tiedostossa, mutta ALTER TABLE -toiminnolla niiden rakennetta ei päivitetä. Tämän seurauksena tietorakenne voi vaihdella tiedoston alusta sen loppuun. Jos käytät usein OPTIMISE TABLE -ohjelmaa, et todennäköisesti kohtaa tällaista ongelmaa.
Kiinnitä huomiota, DBMS-versio vaikuttaa tietojen tallennustapaan, eikä tämä esimerkki välttämättä toimi muissa pääversioissa. Minun tapauksessani käytettiin mariadb 10.1.24:n windows-versiota. Lisäksi vaikka mariadb:ssä työskentelet InnoDB-taulukoiden kanssa, itse asiassa ne ovat XtraDB, mikä sulkee pois menetelmän sovellettavuuden InnoDB mysql:n kanssa.
Tiedostoanalyysi
Pythonissa tietotyyppi tavua() näyttää Unicode-tiedot tavallisen numerosarjan sijasta. Vaikka voit tarkastella tiedostoa tässä muodossa, voit mukavuuden vuoksi muuntaa tavut numeeriseen muotoon muuntamalla tavutaulukon tavalliseksi taulukoksi (list(example_byte_array)). Joka tapauksessa molemmat menetelmät soveltuvat analysointiin.
Kun olet käynyt läpi useita ibd-tiedostoja, löydät seuraavat tiedot:
Lisäksi, jos jaat tiedoston näillä avainsanoilla, saat enimmäkseen tasaisia tietolohkoja. Käytämme jakajana infimumia.
table = table.split("infimum".encode())
Mielenkiintoinen havainto: taulukoissa, joissa on pieni tietomäärä, infimumin ja supremumin välissä on osoitin lohkon rivien lukumäärään.
— testitaulukko 1. rivillä
- testipöytä 2 rivillä
Rivitaulukkotaulukko[0] voidaan ohittaa. Selailun jälkeen en edelleenkään löytänyt raakataulukon tietoja. Todennäköisimmin tätä lohkoa käytetään indeksien ja avainten tallentamiseen.
Alkaen taulukosta[1] ja kääntämällä sen numeeriseksi taulukoksi, voit jo huomata joitain kuvioita, nimittäin:
Nämä ovat merkkijonoon tallennettuja int-arvoja. Ensimmäinen tavu osoittaa, onko luku positiivinen vai negatiivinen. Minun tapauksessani kaikki luvut ovat positiivisia. Lopuista 3 tavusta voit määrittää numeron käyttämällä seuraavaa toimintoa. Käsikirjoitus:
def find_int(val: str): # example '128, 1, 2, 3'
val = [int(v) for v in val.split(", ")]
result_int = val[1]*256**2 + val[2]*256*1 + val[3]
return result_int
Esimerkiksi 128, 0, 0, 1 = 1Tai 128, 0, 75, 108 = 19308.
Taulukossa oli ensisijainen avain automaattisella lisäyksellä, ja se löytyy myös täältä
Verrattaessa testitaulukoiden tietoja paljastui, että DATETIME-olio koostuu 5 tavusta ja alkoi 153:lla (todennäköisimmin osoittaen vuosittaisia intervalleja). Koska DATTIME-alue on '1000-01-01' - '9999-12-31', tavujen määrä voi mielestäni vaihdella, mutta minun tapauksessani data osuu ajanjaksolle 2016-2019, joten oletamme että 5 tavua riittää.
Ajan määrittämiseksi ilman sekunteja kirjoitettiin seuraavat funktiot. Käsikirjoitus:
Olen varma, että jos käytät n aikaa, tämä väärinkäsitys voidaan korjata.
Seuraavaksi funktio, joka palauttaa datetime-objektin merkkijonosta. Käsikirjoitus:
def find_data_time(val:str):
val = [int(v) for v in val.split(", ")]
day = day_(val[2])
hour = hour_(val[2], val[3])
minutes = min_(val[3], val[4])
year, month = year_month(val[1], val[2])
return datetime(year, month, day, hour, minutes)
Onnistui havaitsemaan usein toistuvat arvot int, int, datetime, datetime , näyttää siltä, että tämä on mitä tarvitset. Lisäksi tällaista sekvenssiä ei toisteta kahdesti riviä kohden.
Säännöllisen lausekkeen avulla löydämme tarvittavat tiedot:
Huomaa, että kun haet tällä lausekkeella, ei ole mahdollista määrittää NULL-arvoja vaadituissa kentissä, mutta minun tapauksessani tämä ei ole kriittinen. Sitten käymme läpi sen, mitä löysimme. Käsikirjoitus:
result = []
for val in fined:
pre_result = []
bd_int = re.findall(r"128, d*, d*, d*", val)
bd_date= re.findall(r"(153, 1[6,5,4,3]d, d*, d*, d*)", val)
for it in bd_int:
pre_result.append(find_int(bd_int[it]))
for bd in bd_date:
pre_result.append(find_data_time(bd))
result.append(pre_result)
Itse asiassa siinä kaikki, tulostaulukon tiedot ovat tarvitsemamme tiedot. ###PS.###
Ymmärrän, että tämä menetelmä ei sovi kaikille, mutta artikkelin päätavoite on pikemminkin nopeuttaa toimia kuin ratkaista kaikki ongelmasi. Mielestäni oikea ratkaisu olisi aloittaa lähdekoodin opiskelu itse MariaDB, mutta rajallisen ajan vuoksi nykyinen menetelmä vaikutti nopeimmalta.
Joissakin tapauksissa tiedoston analysoinnin jälkeen voit määrittää likimääräisen rakenteen ja palauttaa sen jollakin yllä olevista linkeistä olevista vakiomenetelmistä. Tämä on paljon oikeampaa ja aiheuttaa vähemmän ongelmia.