Vegerandina daneyan ji tabloyên XtraDB bêyî pelek avahiyek bi karanîna analîza byte-bi-byte ya pelê ibd

Vegerandina daneyan ji tabloyên XtraDB bêyî pelek avahiyek bi karanîna analîza byte-bi-byte ya pelê ibd

pêşdîrok

Wusa bû ku server ji hêla vîrusek ransomware ve hat êrîş kirin, ku bi "qezayek bextewar" ve, beşek pelên .ibd (pelên daneya xav ên tabloyên innodb) bêbandor hiştin, lê di heman demê de pelên .fpm bi tevahî şîfre kirin ( pelên avahiyê). Di vê rewşê de, .idb dikare were dabeş kirin:

  • mijara restorasyonê bi navgîn û rêbernameyên standard. Ji bo rewşên weha, hêja heye bûyin;
  • tabloyên qismî şîfrekirî. Bi piranî ev tabloyên mezin in, ji bo ku (wek ku ez fêm dikim) êrîşkaran ji bo şîfrekirina tam xwedî RAM nebûn;
  • Welê, tabloyên bi tevahî şîfrekirî yên ku nayên sererast kirin.

Mimkun bû ku were destnîşankirin ka tablo ji kîjan vebijarkê ne bi tenê vekirina wê di her edîtorek nivîsê de di bin şîfreya xwestî de (di rewşa min de ew UTF8 e) û bi tenê dîtina pelê ji bo hebûna qadên nivîsê, mînakî:

Vegerandina daneyan ji tabloyên XtraDB bêyî pelek avahiyek bi karanîna analîza byte-bi-byte ya pelê ibd

Di heman demê de, di destpêka pelê de hûn dikarin hejmareke mezin a 0 byte temaşe bikin, û vîrusên ku algorîtmaya şîfrekirina blokê bikar tînin (ya herî gelemperî) bi gelemperî bandorê li wan jî dikin.
Vegerandina daneyan ji tabloyên XtraDB bêyî pelek avahiyek bi karanîna analîza byte-bi-byte ya pelê ibd

Di doza min de, êrîşkaran di dawiya her pelê şîfrekirî de rêzek 4-byte (1, 0, 0, 0) hiştin, ku peywirê hêsan kir. Ji bo lêgerîna pelên negirtî, skrîpt bes bû:

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)

Bi vî rengî, derket holê ku pelên ku ji celebê yekem in hatine dîtin. Ya duyemîn gelek karên destan dihewîne, lê ya ku hat dîtin jixwe bes bû. Her tişt dê baş be, lê divê hûn zanibin strukturek bêkêmasî ya rast û (bê guman) dozek derket ku ez neçar bûm ku bi tabloyek ku pir caran diguhere bixebitim. Ji bîr nedihat ku tîpa zeviyê hate guhertin an stûnek nû lê zêde bû.

Wilds City, mixabin, nikaribû bi dozek weha re bibe alîkar, ji ber vê yekê ev gotar tê nivîsandin.

Biçe ser xalê

Struktura tabloyek ji 3 meh berê heye ku bi ya heyî re li hev nake (dibe ku yek zevî, û dibe ku bêtir). Struktura tabloyê:

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)
); 

Di vê rewşê de, divê hûn derxistin:

  • id_point int(11);
  • id_user int(11);
  • date_start DATETIME;
  • date_finish DATETIME.

Ji bo başbûnê, analîzek byte-bi-byte ya pelê .ibd tê bikar anîn, paşê wan vediguhezîne formek bêtir xwendin. Ji ber ku ji bo dîtina tiştê ku ji me re lazim e, em tenê hewce ne ku celebên daneyê yên wekî int û datatime analîz bikin, gotar dê tenê wan rave bike, lê carinan em ê celebên daneya din jî vebêjin, ku dikarin di bûyerên din ên bi vî rengî de bibin alîkar.

Pirsgirêk 1: qadên bi cureyên DATETIME û TEXT nirxên NULL hene, û ew bi hêsanî di pelê de têne paşguh kirin, ji ber vê yekê, ne gengaz bû ku di doza min de strukturek were vegerandin. Di stûnên nû de, nirxa xwerû betal bû, û beşek ji danûstendinê dikare ji ber mîhengê innodb_flush_log_at_trx_commit = 0 winda bibe, ji ber vê yekê pêdivî ye ku demek zêde were xerc kirin ji bo destnîşankirina strukturê.

Pirsgirêk 2: Divê were hesibandin ku rêzên ku bi rêya DELETE hatine jêbirin dê hemî di pelê ibd de bin, lê bi ALTER TABLE re avahiya wan nayê nûve kirin. Wekî encamek, avahiya daneyê dikare ji destpêka pelê heya dawiya wê diguhere. Ger hûn pir caran OPTIMIZE TABLE bikar tînin, wê hingê hûn ne mimkûn e ku hûn bi pirsgirêkek wusa re rû bi rû bimînin.

Bawer bikin, guhertoya DBMS bandorê li awayê hilanîna daneyan dike, û dibe ku ev mînak ji bo guhertoyên din ên sereke nexebite. Di doza min de, guhertoya windows mariadb 10.1.24 hate bikar anîn. Di heman demê de, her çend di mariadb de hûn bi tabloyên InnoDB re dixebitin, bi rastî ew in XtraDB, ku sepandina rêbazê bi InnoDB mysql re derdixe holê.

Analîzkirina pelê

Di python de, celebê daneyê bytes () Daneyên Unicode li şûna komek birêkûpêk a hejmaran nîşan dide. Her çend hûn dikarin pelê di vê formê de bibînin jî, ji bo rehetiyê hûn dikarin bi veguheztina rêzika baytê veguhezînin rêzek birêkûpêk (lîste(mînak_byte_array)). Di her rewşê de, her du rêbaz ji bo analîzê minasib in.

Piştî ku hûn li çend pelên ibd digerin, hûn dikarin jêrîn bibînin:

Vegerandina daneyan ji tabloyên XtraDB bêyî pelek avahiyek bi karanîna analîza byte-bi-byte ya pelê ibd

Wekî din, heke hûn pelê bi van peyvan veqetînin, hûn ê bi piranî blokên daneyê jî bistînin. Em ê infimum wekî dabeşker bikar bînin.

table = table.split("infimum".encode())

Çavdêriyek balkêş: ji bo tabloyên bi daneya piçûk, di navbera infimum û supremum de nîşanek jimara rêzên di blokê de heye.

Vegerandina daneyan ji tabloyên XtraDB bêyî pelek avahiyek bi karanîna analîza byte-bi-byte ya pelê ibd - tabloya testê bi rêza 1

Vegerandina daneyan ji tabloyên XtraDB bêyî pelek avahiyek bi karanîna analîza byte-bi-byte ya pelê ibd - tabloya testê bi 2 rêzan

Tabloya rêzika rêzê[0] dikare were paşguh kirin. Piştî ku lê nihêrî, min hîn jî nekarî daneyên tabloya xav bibînim. Bi îhtîmaleke mezin, ev blok ji bo hilanîna index û kilîtan tê bikar anîn.
Bi tabloya[1] dest pê bikin û wê li rêzek jimareyî wergerînin, hûn dikarin berê xwe bidin hin nimûneyan, bi navî:

Vegerandina daneyan ji tabloyên XtraDB bêyî pelek avahiyek bi karanîna analîza byte-bi-byte ya pelê ibd

Van nirxan int in ku di rêzek de têne hilanîn. Bîta yekem nîşan dide ku hejmar erênî ye an neyînî ye. Di rewşa min de, hemî hejmar erênî ne. Ji 3 baytên mayî, hûn dikarin bi fonksiyona jêrîn hejmarê diyar bikin. Nivîs:

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

Ji bo nimûne, 128, 0, 0, 1 = 1an 128, 0, 75, 108 = 19308.
Tablo xwedan mifteyek bingehîn a bi zêdekirina otomatîkî bû, û ew li vir jî dikare were dîtin

Vegerandina daneyan ji tabloyên XtraDB bêyî pelek avahiyek bi karanîna analîza byte-bi-byte ya pelê ibd

Dema ku daneyên ji tabloyên ceribandinê dan ber hev, hate eşkere kirin ku tişta DATETIME ji 5 byteyan pêk tê û bi 153 dest pê kir (bi îhtîmalek mezin navberên salane destnîşan dike). Ji ber ku rêza DATTIME '1000-01-01' heya '9999-12-31' ye, ez difikirim ku dibe ku hejmara bayteyan cûda bibe, lê di rewşa min de, dane di heyama 2016-an heya 2019-an de dikeve, ji ber vê yekê em ê texmîn bikin ew 5 bytes bes.

Ji bo diyarkirina dema bê saniye, fonksiyonên jêrîn hatine nivîsandin. Nivîs:

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}

Ne gengaz bû ku ji bo sal û mehê fonksiyonek fonksiyonel binivîsim, ji ber vê yekê min neçar ma ku wê hack bikim. Nivîs:

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

Ez piştrast im ku heke hûn n dem derbas bikin, ev xelet têgihiştin dikare were rast kirin.
Dûv re, fonksiyonek ku ji rêzek tiştekê tarîxê vedigerîne. Nivîs:

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)

Rêve kirin ku nirxên ku pir caran têne dubare kirin ji int, int, datetime, datetime Vegerandina daneyan ji tabloyên XtraDB bêyî pelek avahiyek bi karanîna analîza byte-bi-byte ya pelê ibd, wusa dixuye ku ev tiştê ku hûn hewce ne. Wekî din, rêzek wusa di her rêzê de du caran nayê dubare kirin.

Bi karanîna birêkûpêkek birêkûpêk, em daneyên pêwîst dibînin:

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)

Ji kerema xwe bala xwe bidin ku dema ku hûn vê îfadeyê bikar bînin lêgerîn, dê ne gengaz be ku di qadên pêwîst de nirxên NULL werin destnîşankirin, lê di rewşa min de ev ne krîtîk e. Dûv re em tişta ku me di çerxekê de dît derbas dibin. Nivîs:

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)

Bi rastî, ew hemî ye, daneyên ji berhevoka encamê daneyên ku em hewce ne. ###PS.###
Ez fêm dikim ku ev rêbaz ji bo her kesî ne maqûl e, lê mebesta sereke ya gotarê ev e ku meriv ji bo çareserkirina hemî pirsgirêkên we bilez bike. Ez difikirim ku çareseriya herî rast ew e ku hûn bixwe dest bi xwendina koda çavkaniyê bikin mariadb, lê ji ber wextê tixûbdar, rêbaza heyî zûtirîn xuya bû.

Di hin rewşan de, piştî analîzkirina pelê, hûn ê bikaribin strukturek texmînî diyar bikin û wê bi karanîna yek ji rêgezên standard ên ji girêdanên jorîn vegerînin. Ev ê pir rasttir be û bibe sedema kêmtir pirsgirêkan.

Source: www.habr.com

Add a comment