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:

Adfer data o dablau XtraDB heb ffeil strwythur gan ddefnyddio dadansoddiad beit-wrth-beit o'r ffeil ibd

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.
Adfer data o dablau XtraDB heb ffeil strwythur gan ddefnyddio dadansoddiad beit-wrth-beit o'r ffeil ibd

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:

Adfer data o dablau XtraDB heb ffeil strwythur gan ddefnyddio dadansoddiad beit-wrth-beit o'r ffeil ibd

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.

Adfer data o dablau XtraDB heb ffeil strwythur gan ddefnyddio dadansoddiad beit-wrth-beit o'r ffeil ibd — bwrdd prawf gyda rhes 1af

Adfer data o dablau XtraDB heb ffeil strwythur gan ddefnyddio dadansoddiad beit-wrth-beit o'r ffeil ibd - 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:

Adfer data o dablau XtraDB heb ffeil strwythur gan ddefnyddio dadansoddiad beit-wrth-beit o'r ffeil ibd

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

Adfer data o dablau XtraDB heb ffeil strwythur gan ddefnyddio dadansoddiad beit-wrth-beit o'r ffeil ibd

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:

day_ = lambda x: x % 64 // 2  # {x,x,X,x,x }

def hour_(x1, x2):  # {x,x,X1,X2,x}
    if x1 % 2 == 0:
        return x2 // 16
    elif x1 % 2 == 1:
        return x2 // 16 + 16
    else:
        raise ValueError

min_ = lambda x1, x2: (x1 % 16) * 4 + (x2 // 64)  # {x,x,x,X1,X2}

Nid oedd yn bosibl ysgrifennu swyddogaeth swyddogaethol ar gyfer y flwyddyn a'r mis, felly roedd yn rhaid i mi ei hacio. Sgript:

ym_list = {'2016, 1': '153, 152, 64', '2016, 2': '153, 152, 128', 
           '2016, 3': '153, 152, 192', '2016, 4': '153, 153, 0',
           '2016, 5': '153, 153, 64', '2016, 6': '153, 153, 128', 
           '2016, 7': '153, 153, 192', '2016, 8': '153, 154, 0', 
           '2016, 9': '153, 154, 64', '2016, 10': '153, 154, 128', 
           '2016, 11': '153, 154, 192', '2016, 12': '153, 155, 0',
           '2017, 1': '153, 155, 128', '2017, 2': '153, 155, 192', 
           '2017, 3': '153, 156, 0', '2017, 4': '153, 156, 64',
           '2017, 5': '153, 156, 128', '2017, 6': '153, 156, 192',
           '2017, 7': '153, 157, 0', '2017, 8': '153, 157, 64',
           '2017, 9': '153, 157, 128', '2017, 10': '153, 157, 192', 
           '2017, 11': '153, 158, 0', '2017, 12': '153, 158, 64', 
           '2018, 1': '153, 158, 192', '2018, 2': '153, 159, 0',
           '2018, 3': '153, 159, 64', '2018, 4': '153, 159, 128', 
           '2018, 5': '153, 159, 192', '2018, 6': '153, 160, 0',
           '2018, 7': '153, 160, 64', '2018, 8': '153, 160, 128',
           '2018, 9': '153, 160, 192', '2018, 10': '153, 161, 0', 
           '2018, 11': '153, 161, 64', '2018, 12': '153, 161, 128',
           '2019, 1': '153, 162, 0', '2019, 2': '153, 162, 64', 
           '2019, 3': '153, 162, 128', '2019, 4': '153, 162, 192', 
           '2019, 5': '153, 163, 0', '2019, 6': '153, 163, 64',
           '2019, 7': '153, 163, 128', '2019, 8': '153, 163, 192',
           '2019, 9': '153, 164, 0', '2019, 10': '153, 164, 64', 
           '2019, 11': '153, 164, 128', '2019, 12': '153, 164, 192',
           '2020, 1': '153, 165, 64', '2020, 2': '153, 165, 128',
           '2020, 3': '153, 165, 192','2020, 4': '153, 166, 0', 
           '2020, 5': '153, 166, 64', '2020, 6': '153, 1, 128',
           '2020, 7': '153, 166, 192', '2020, 8': '153, 167, 0', 
           '2020, 9': '153, 167, 64','2020, 10': '153, 167, 128',
           '2020, 11': '153, 167, 192', '2020, 12': '153, 168, 0'}

def year_month(x1, x2):  # {x,X,X,x,x }

    for key, value in ym_list.items():
        key = [int(k) for k in key.replace("'", "").split(", ")]
        value = [int(v) for v in value.split(", ")]
        if x1 == value[1] and x2 // 64 == value[2] // 64:
            return key
    return 0, 0

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 Adfer data o dablau XtraDB heb ffeil strwythur gan ddefnyddio dadansoddiad beit-wrth-beit o'r ffeil ibd, 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:

fined = re.findall(r'128, d*, d*, d*, 128, d*, d*, d*, 153, 1[6,5,4,3]d, d*, d*, d*, 153, 1[6,5,4,3]d, d*, d*, d*', int_array)

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.

Ffynhonnell: hab.com

Ychwanegu sylw