ProHoster > blog > Gweinyddiaeth > Adfer data o dablau XtraDB heb ffeil strwythur gan ddefnyddio dadansoddiad beit-wrth-beit o'r ffeil ibd
Adfer data o dablau XtraDB heb ffeil strwythur gan ddefnyddio dadansoddiad beit-wrth-beit o'r ffeil ibd
cynhanes
Digwyddodd felly bod firws ransomware wedi ymosod ar y gweinydd, a oedd, trwy “ddamwain lwcus,” yn rhannol yn gadael y ffeiliau .ibd (ffeiliau data crai tablau innodb) heb eu cyffwrdd, ond ar yr un pryd wedi amgryptio’r ffeiliau .fpm yn llwyr ( ffeiliau strwythur). Yn yr achos hwn, gellid rhannu .idb yn:
yn amodol ar adferiad trwy offer a chanllawiau safonol. Ar gyfer achosion o'r fath, mae rhagorol dod;
tablau wedi'u hamgryptio'n rhannol. Yn bennaf mae'r rhain yn dablau mawr, ac nid oedd gan yr ymosodwyr (fel y deallaf) ddigon o RAM ar gyfer amgryptio llawn ar eu cyfer;
Wel, tablau wedi'u hamgryptio'n llawn na ellir eu hadfer.
Roedd yn bosibl penderfynu pa opsiwn y mae'r tablau yn perthyn iddo trwy ei agor mewn unrhyw olygydd testun o dan yr amgodio dymunol (UTF8 yn fy achos i) a dim ond edrych ar y ffeil am bresenoldeb meysydd testun, er enghraifft:
Hefyd, ar ddechrau'r ffeil gallwch chi arsylwi nifer fawr o 0 bytes, ac mae firysau sy'n defnyddio'r algorithm amgryptio bloc (y mwyaf cyffredin) fel arfer yn effeithio arnyn nhw hefyd.
Yn fy achos i, gadawodd yr ymosodwyr llinyn 4-byte (1, 0, 0, 0) ar ddiwedd pob ffeil wedi'i hamgryptio, a oedd yn symleiddio'r dasg. I chwilio am ffeiliau heb eu heintio, roedd y sgript yn ddigon:
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)
Felly, mae'n troi allan i ddod o hyd i ffeiliau yn perthyn i'r math cyntaf. Mae'r ail yn golygu llawer o waith llaw, ond roedd yr hyn a ddarganfuwyd eisoes yn ddigon. Byddai popeth yn iawn, ond mae angen i chi wybod strwythur hollol fanwl gywir ac (wrth gwrs) cododd achos bod yn rhaid i mi weithio gyda bwrdd sy'n newid yn aml. Nid oedd neb yn cofio a gafodd y math o faes ei newid neu a ychwanegwyd colofn newydd.
Yn anffodus, ni allai Wilds City helpu gydag achos o'r fath, a dyna pam mae'r erthygl hon yn cael ei hysgrifennu.
Cyrraedd y pwynt
Mae strwythur tabl o 3 mis yn ôl nad yw'n cyd-fynd â'r un presennol (un maes o bosibl, ac o bosibl mwy). Strwythur tabl:
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)
);
yn yr achos hwn, mae angen i chi dynnu:
id_point int(11);
id_user int(11);
date_start AMSER DYDDIAD;
date_finish AMSER DYDDIAD.
Ar gyfer adferiad, defnyddir dadansoddiad beit-wrth-beit o'r ffeil .ibd, ac yna eu trosi'n ffurf fwy darllenadwy. Gan fod i ddod o hyd i'r hyn sydd ei angen arnom, dim ond angen i ni ddadansoddi mathau o ddata fel int a datatime, bydd yr erthygl yn eu disgrifio yn unig, ond weithiau byddwn hefyd yn cyfeirio at fathau eraill o ddata, a all helpu mewn digwyddiadau tebyg eraill.
Problem 1: caeau gyda mathau Roedd gan DATETIME a TEXT werthoedd NULL, ac maent yn cael eu hepgor yn syml yn y ffeil, oherwydd hyn, nid oedd yn bosibl pennu'r strwythur i'w adfer yn fy achos i. Yn y colofnau newydd, roedd y gwerth rhagosodedig yn nwl, a gallai rhan o'r trafodiad gael ei golli oherwydd y gosodiad innodb_flush_log_at_trx_commit = 0, felly byddai'n rhaid treulio amser ychwanegol i bennu'r strwythur.
Problem 2: dylid cymryd i ystyriaeth y bydd rhesi a ddilëwyd trwy DELETE i gyd yn y ffeil ibd, ond gydag ALTER TABLE ni fydd eu strwythur yn cael ei ddiweddaru. O ganlyniad, gall y strwythur data amrywio o ddechrau'r ffeil i'w diwedd. Os ydych chi'n aml yn defnyddio OPTIMIZE TABLE, yna mae'n annhebygol y byddwch chi'n dod ar draws problem o'r fath.
Talu sylw, mae fersiwn DBMS yn effeithio ar y ffordd y caiff data ei storio, ac efallai na fydd yr enghraifft hon yn gweithio ar gyfer fersiynau mawr eraill. Yn fy achos i, defnyddiwyd y fersiwn windows o mariadb 10.1.24. Hefyd, er mewn mariadb rydych chi'n gweithio gyda thablau InnoDB, mewn gwirionedd maen nhw XtraDB, sy'n eithrio cymhwysedd y dull gyda mysql InnoDB.
Dadansoddiad ffeil
Yn python, math o ddata beit () yn dangos data Unicode yn lle set reolaidd o rifau. Er y gallwch weld y ffeil yn y ffurflen hon, er hwylustod gallwch drosi'r beit yn ffurf rifol trwy drosi'r arae beit yn arae reolaidd (rhestr (example_byte_array)). Mewn unrhyw achos, mae'r ddau ddull yn addas ar gyfer dadansoddi.
Ar ôl edrych trwy sawl ffeil ibd, gallwch ddod o hyd i'r canlynol:
Ar ben hynny, os rhannwch y ffeil â'r geiriau allweddol hyn, fe gewch hyd yn oed flociau o ddata yn bennaf. Byddwn yn defnyddio infimum fel rhannwr.
table = table.split("infimum".encode())
Sylw diddorol: ar gyfer tablau gydag ychydig bach o ddata, rhwng infimum a supremum mae pwyntydd i nifer y rhesi yn y bloc.
— bwrdd prawf gyda rhes 1af
- bwrdd prawf gyda 2 res
Gellir hepgor y tabl rhesi rhes[0]. Ar ôl edrych drwyddo, nid oeddwn yn gallu dod o hyd i'r data tabl crai o hyd. Yn fwyaf tebygol, defnyddir y bloc hwn i storio mynegeion ac allweddi.
Gan ddechrau gyda thabl [1] a'i drosi'n arae rhifol, gallwch chi eisoes sylwi ar rai patrymau, sef:
Gwerthoedd int yw'r rhain sy'n cael eu storio mewn llinyn. Mae'r beit cyntaf yn nodi a yw'r rhif yn bositif neu'n negyddol. Yn fy achos i, mae pob rhif yn gadarnhaol. O'r 3 beit sy'n weddill, gallwch chi bennu'r rhif gan ddefnyddio'r swyddogaeth ganlynol. Sgript:
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
Er enghraifft, 128, 0, 0, 1 = 1Neu 128, 0, 75, 108 = 19308.
Roedd gan y tabl allwedd gynradd gyda chynyddiad ceir, a gellir ei ddarganfod yma hefyd
Ar ôl cymharu'r data o'r tablau prawf, datgelwyd bod y gwrthrych DATETIME yn cynnwys 5 beit a dechreuodd gyda 153 (yn ôl pob tebyg yn nodi cyfnodau blynyddol). Gan mai ystod DATTIME yw '1000-01-01' i '9999-12-31', rwy'n meddwl y gall nifer y beit amrywio, ond yn fy achos i, mae'r data'n disgyn yn y cyfnod rhwng 2016 a 2019, felly byddwn yn tybio bod 5 beit yn ddigon.
Er mwyn pennu'r amser heb eiliadau, ysgrifennwyd y swyddogaethau canlynol. Sgript:
Yr wyf yn siŵr, os treuliwch n swm o amser, y gellir cywiro’r camddealltwriaeth hwn.
Nesaf, swyddogaeth sy'n dychwelyd gwrthrych datetime o linyn. Sgript:
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)
Wedi llwyddo i ganfod gwerthoedd a ailadroddir yn aml o int, int, datetime, datetime , mae'n edrych fel mai dyma sydd ei angen arnoch chi. Ar ben hynny, nid yw dilyniant o'r fath yn cael ei ailadrodd ddwywaith y llinell.
Gan ddefnyddio mynegiant rheolaidd, rydym yn dod o hyd i'r data angenrheidiol:
Sylwch, wrth chwilio gan ddefnyddio'r ymadrodd hwn, ni fydd yn bosibl pennu gwerthoedd NULL yn y meysydd gofynnol, ond yn fy achos i nid yw hyn yn hollbwysig. Yna rydyn ni'n mynd trwy'r hyn rydyn ni'n ei ddarganfod mewn dolen. Sgript:
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)
A dweud y gwir, dyna i gyd, y data o'r arae canlyniadau yw'r data sydd ei angen arnom. ###PS.###
Deallaf nad yw'r dull hwn yn addas i bawb, ond prif nod yr erthygl yw annog gweithredu yn hytrach na datrys eich holl broblemau. Rwy'n meddwl mai'r ateb mwyaf cywir fyddai dechrau astudio'r cod ffynhonnell eich hun mariadb, ond oherwydd amser cyfyngedig, roedd yn ymddangos mai'r dull presennol oedd y cyflymaf.
Mewn rhai achosion, ar ôl dadansoddi'r ffeil, byddwch yn gallu pennu'r strwythur bras a'i adfer gan ddefnyddio un o'r dulliau safonol o'r dolenni uchod. Bydd hyn yn llawer mwy cywir ac yn achosi llai o broblemau.