Mbalekake data saka tabel XtraDB tanpa file struktur nggunakake analisis byte-by-byte file ibd

Mbalekake data saka tabel XtraDB tanpa file struktur nggunakake analisis byte-by-byte file ibd

prasejarah

Kedaden sing server diserang dening virus ransomware, kang, dening "kacilakan begja," sebagian ninggalake file .ibd (file data mentah saka tabel innodb) ora kena, nanging ing wektu sing padha rampung ndhelik file .fpm ( file struktur). Ing kasus iki, .idb bisa dipérang dadi:

  • tundhuk pemugaran liwat piranti lan panuntun standar. Kanggo kasus kaya mengkono, ana sing apik banget dadi;
  • tabel sebagian ndhelik. Biasane iki tabel gedhe, sing (aku ngerti) panyerang ora cukup RAM kanggo enkripsi lengkap;
  • Inggih, tabel kanthi ndhelik sing ora bisa dipulihake.

Sampeyan bisa nemtokake pilihan sing ana ing tabel kanthi mung mbukak ing editor teks apa wae miturut enkoding sing dikarepake (ing kasusku yaiku UTF8) lan mung ndeleng file kanggo anane kolom teks, umpamane:

Mbalekake data saka tabel XtraDB tanpa file struktur nggunakake analisis byte-by-byte file ibd

Uga, ing wiwitan file sampeyan bisa mirsani nomer akeh 0 bita, lan virus sing nggunakake algoritma enkripsi pemblokiran (paling umum) biasane mengaruhi wong-wong mau uga.
Mbalekake data saka tabel XtraDB tanpa file struktur nggunakake analisis byte-by-byte file ibd

Ing kasusku, panyerang ninggalake senar 4-bait (1, 0, 0, 0) ing pungkasan saben file sing dienkripsi, sing nyederhanakake tugas kasebut. Kanggo nggoleki file sing ora kena infeksi, skrip kasebut cukup:

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)

Mangkono, ternyata nemokake file sing ana ing jinis pisanan. Kapindho nyakup akeh karya manual, nanging sing ditemokake wis cukup. Kabeh bakal apik, nanging sampeyan kudu ngerti struktur pancen presisi lan (mesthi) muncul yen aku kudu nggarap meja sing kerep diganti. Ora ana sing ngelingi apa jinis lapangan diganti utawa kolom anyar ditambahake.

Wilds City, sayangé, ora bisa nulungi kasus kasebut, mula artikel iki ditulis.

Njaluk menyang titik

Ana struktur tabel saka 3 sasi kepungkur sing ora pas karo saiki (bisa uga siji lapangan, lan bisa uga luwih). Struktur Tabel:

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

ing kasus iki, sampeyan kudu extract:

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

Kanggo pemulihan, analisis byte-by-byte file .ibd digunakake, banjur diowahi dadi wangun sing luwih bisa diwaca. Awit kanggo nemokake apa sing kita butuhake, kita mung kudu nganalisa jinis data kayata int lan datatime, artikel kasebut mung bakal njlèntrèhaké wong-wong mau, nanging kadhangkala uga bakal ngrujuk marang jinis data liyane, sing bisa mbantu kedadeyan sing padha.

Masalah 1: lapangan karo jinis DATETIME lan TEXT wis Nilai NULL, lan padha mung Mlayu ing file, amarga iki, iku ora bisa kanggo nemtokake struktur kanggo mulihake ing cilik. Ing kolom anyar, nilai standar nol, lan bagean saka transaksi bisa ilang amarga setelan innodb_flush_log_at_trx_commit = 0, supaya wektu tambahan kudu ngginakaken kanggo nemtokake struktur.

Masalah 2: kudu dianggep yen baris sing dibusak liwat DELETE kabeh bakal ana ing file ibd, nanging kanthi ALTER TABLE strukture ora bakal dianyari. Akibaté, struktur data bisa beda-beda saka wiwitan file nganti pungkasan. Yen sampeyan kerep nggunakake OPTIMIZE TABLE, mula sampeyan ora bakal nemoni masalah kasebut.

Delengen, versi DBMS mengaruhi cara data disimpen, lan conto iki ora bisa digunakake kanggo versi utama liyane. Ing kasusku, versi windows mariadb 10.1.24 digunakake. Uga, sanajan ing mariadb sampeyan nggarap tabel InnoDB, nyatane XtraDB, sing ora kalebu aplikasi metode karo InnoDB mysql.

Analisis file

Ing python, jinis data bita () nampilake data Unicode ing panggonan saka pesawat biasa saka nomer. Sanajan sampeyan bisa ndeleng file ing wangun iki, kanggo penak sampeyan bisa ngowahi bait menyang wangun numerik kanthi ngowahi array byte menyang array biasa (dhaftar(example_byte_array)). Ing kasus apa wae, loro cara kasebut cocog kanggo analisis.

Sawise nggoleki sawetara file ibd, sampeyan bisa nemokake ing ngisor iki:

Mbalekake data saka tabel XtraDB tanpa file struktur nggunakake analisis byte-by-byte file ibd

Kajaba iku, yen sampeyan mbagi file kasebut kanthi tembung kunci kasebut, sampeyan bakal entuk blok data. Kita bakal nggunakake infimum minangka divisor.

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

Pengamatan sing menarik: kanggo tabel kanthi jumlah data sing cilik, ing antarane infimum lan supremum ana penunjuk nomer baris ing blok kasebut.

Mbalekake data saka tabel XtraDB tanpa file struktur nggunakake analisis byte-by-byte file ibd - Tabel test karo baris 1st

Mbalekake data saka tabel XtraDB tanpa file struktur nggunakake analisis byte-by-byte file ibd - Tabel test karo 2 larik

Tabel larik baris [0] bisa dilewati. Sawise nggoleki, aku isih ora bisa nemokake data tabel mentah. Paling kamungkinan, blok iki digunakake kanggo nyimpen indeks lan kunci.
Miwiti karo tabel [1] lan nerjemahake menyang array numerik, sampeyan bisa ndeleng sawetara pola, yaiku:

Mbalekake data saka tabel XtraDB tanpa file struktur nggunakake analisis byte-by-byte file ibd

Iki minangka nilai int sing disimpen ing senar. Byte pisanan nuduhake manawa nomer kasebut positif utawa negatif. Ing kasusku, kabeh nomer positif. Saka 3 bita sing isih ana, sampeyan bisa nemtokake nomer nggunakake fungsi ing ngisor iki. Skrip:

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

Contone, 128, 0, 0, 1 = 1, utawa 128, 0, 75, 108 = 19308.
Tabel kasebut nduweni kunci utama kanthi otomatis nambah, lan uga bisa ditemokake ing kene

Mbalekake data saka tabel XtraDB tanpa file struktur nggunakake analisis byte-by-byte file ibd

Sawise mbandhingake data saka tabel tes, dicethakaké yèn obyek DATETIME kasusun saka 5 bait lan wiwit karo 153 (paling kamungkinan nuduhake interval taunan). Wiwit kisaran DATTIME yaiku '1000-01-01' nganti '9999-12-31', aku mikir jumlah bait bisa beda-beda, nanging ing kasusku, data kasebut tiba ing periode saka 2016 nganti 2019, mula kita bakal nganggep sing 5 bait cukup.

Kanggo nemtokake wektu tanpa detik, fungsi ing ngisor iki ditulis. Skrip:

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}

Ora bisa nulis fungsi fungsional kanggo taun lan sasi, mula aku kudu hack. Skrip:

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

Aku manawa yen nglampahi n jumlah wektu, misunderstanding iki bisa didandani.
Sabanjure, fungsi sing ngasilake obyek datetime saka senar. Skrip:

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)

Ngatur kanggo ndeteksi nilai sing kerep diulang saka int, int, datetime, datetime Mbalekake data saka tabel XtraDB tanpa file struktur nggunakake analisis byte-by-byte file ibd, katon kaya iki sing sampeyan butuhake. Kajaba iku, urutan kasebut ora diulang kaping pindho saben baris.

Nggunakake ekspresi reguler, kita nemokake data sing dibutuhake:

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)

Elinga yen nalika nggoleki nggunakake ekspresi iki, ora bisa nemtokake nilai NULL ing kolom sing dibutuhake, nanging ing kasus iki, iki ora kritis. Banjur kita ngliwati apa sing ditemokake ing daur ulang. Skrip:

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)

Bener, kabeh, data saka larik asil yaiku data sing kita butuhake. ##PS.##
Aku ngerti manawa cara iki ora cocog kanggo kabeh wong, nanging tujuan utama artikel kasebut yaiku supaya tumindak tinimbang ngrampungake kabeh masalah sampeyan. Aku mikir solusi sing paling bener yaiku miwiti sinau kode sumber dhewe mariadb, nanging amarga wektu winates, cara saiki katon paling cepet.

Ing sawetara kasus, sawise nganalisa file, sampeyan bakal bisa nemtokake struktur kira-kira lan mulihake nggunakake salah siji saka cara standar saka pranala ing ndhuwur. Iki bakal luwih bener lan nyebabake masalah sing luwih sithik.

Source: www.habr.com

Add a comment