ibd ගොනුවේ byte-by-byte විශ්ලේෂණය භාවිතයෙන් ව්‍යුහ ගොනුවක් නොමැතිව XtraDB වගු වලින් දත්ත ප්‍රතිසාධනය කිරීම

ibd ගොනුවේ byte-by-byte විශ්ලේෂණය භාවිතයෙන් ව්‍යුහ ගොනුවක් නොමැතිව XtraDB වගු වලින් දත්ත ප්‍රතිසාධනය කිරීම

මුදලටය

ransomware වෛරසයකින් සේවාදායකයට ප්‍රහාරයක් එල්ල වූ අතර, එය “වාසනාවන්ත අනතුරකින්” .ibd ගොනු (innodb වගු වල අමු දත්ත ගොනු) අර්ධ වශයෙන් ස්පර්ශ නොකළ නමුත් ඒ සමඟම .fpm ගොනු සම්පූර්ණයෙන්ම සංකේතනය කරන ලදී ( ව්යුහය ගොනු). මෙම අවස්ථාවේදී, .idb පහත පරිදි බෙදිය හැකිය:

  • සම්මත මෙවලම් සහ මාර්ගෝපදේශ හරහා ප්රතිෂ්ඨාපනයට යටත් වේ. එවැනි අවස්ථා සඳහා, විශිෂ්ට එකක් තිබේ බවට පත් වේ;
  • අර්ධ වශයෙන් සංකේතනය කළ වගු. බොහෝ දුරට මේවා විශාල වගු වේ, ඒ සඳහා (මට තේරෙන පරිදි) ප්‍රහාරකයන්ට සම්පූර්ණ සංකේතනය සඳහා ප්‍රමාණවත් RAM නොතිබුණි;
  • හොඳයි, ප්‍රතිසාධනය කළ නොහැකි සම්පූර්ණයෙන්ම සංකේතනය කළ වගු.

අවශ්‍ය කේතීකරණය යටතේ ඕනෑම පෙළ සංස්කාරකයක එය විවෘත කිරීමෙන් (මගේ නඩුවේදී එය UTF8 වේ) සහ පෙළ ක්ෂේත්‍ර තිබීම සඳහා ගොනුව බැලීමෙන් වගු අයත් වන්නේ කුමන විකල්පයටද යන්න තීරණය කළ හැකිය, උදාහරණයක් ලෙස:

ibd ගොනුවේ byte-by-byte විශ්ලේෂණය භාවිතයෙන් ව්‍යුහ ගොනුවක් නොමැතිව XtraDB වගු වලින් දත්ත ප්‍රතිසාධනය කිරීම

එසේම, ගොනුවේ ආරම්භයේ දී ඔබට බයිට් 0 ක් විශාල සංඛ්යාවක් නිරීක්ෂණය කළ හැකි අතර, බ්ලොක් සංකේතාංකන ඇල්ගොරිතම (වඩාත් පොදු) භාවිතා කරන වෛරස් සාමාන්යයෙන් ඒවාට ද බලපායි.
ibd ගොනුවේ byte-by-byte විශ්ලේෂණය භාවිතයෙන් ව්‍යුහ ගොනුවක් නොමැතිව XtraDB වගු වලින් දත්ත ප්‍රතිසාධනය කිරීම

මගේ නඩුවේදී, ප්‍රහාරකයින් එක් එක් සංකේතාත්මක ගොනුව අවසානයේ 4-බයිට් තන්තුවක් (1, 0, 0, 0) තබා ඇති අතර එමඟින් කාර්යය සරල විය. ආසාදිත ගොනු සෙවීමට, ස්ක්‍රිප්ට් එක ප්‍රමාණවත් විය:

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)

මේ අනුව, පළමු වර්ගයට අයත් ලිපිගොනු සොයා ගැනීමට හැකි විය. දෙවැන්න අතින් වැඩ ගොඩක් ඇතුළත් වේ, නමුත් සොයාගත් දේ දැනටමත් ප්රමාණවත් විය. සෑම දෙයක්ම හොඳින් වනු ඇත, නමුත් ඔබ දැනගත යුතුය සම්පූර්ණයෙන්ම නිවැරදි ව්යුහය සහ (ඇත්ත වශයෙන්ම) මට නිතර වෙනස් වන මේසයක් සමඟ වැඩ කිරීමට සිදු වූ නඩුවක් මතු විය. ක්ෂේත්‍ර වර්ගය වෙනස් කළාද නැතිනම් අලුත් තීරුවක් එකතු කළාද යන්න කාටවත් මතක නැත.

Wilds City, අවාසනාවකට, එවැනි නඩුවකට උදව් කිරීමට නොහැකි විය, මෙම ලිපිය ලියන්නේ එබැවිනි.

කාරණයට එන්න

දැනට පවතින එක (සමහරවිට එක් ක්ෂේත්‍රයක් සහ සමහර විට තවත්) සමග නොගැලපෙන වගුවක ව්‍යුහයක් මාස 3කට පෙර සිට ඇත. වගු ව්යුහය:

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

මෙම අවස්ථාවේදී, ඔබ උපුටා ගත යුතුය:

  • id_point int (11);
  • id_user int (11);
  • date_start දිනය වෙලාව;
  • date_finish දිනය වෙලාව.

ප්‍රතිසාධනය සඳහා, .ibd ගොනුවේ byte-by-byte විශ්ලේෂණයක් භාවිතා කරනු ලැබේ, පසුව ඒවා වඩාත් කියවිය හැකි ආකාරයක් බවට පරිවර්තනය කරයි. අපට අවශ්‍ය දේ සොයා ගැනීමට, අපට අවශ්‍ය වන්නේ int සහ datatime වැනි දත්ත වර්ග විශ්ලේෂණය කිරීම පමණි, ලිපිය ඒවා පමණක් විස්තර කරනු ඇත, නමුත් සමහර විට අපි වෙනත් සමාන සිද්ධීන් සඳහා උපකාර කළ හැකි වෙනත් දත්ත වර්ග ද යොමු කරමු.

ගැටලුව 1: DATETIME සහ TEXT වර්ග සහිත ක්ෂේත්‍රවල NULL අගයන් තිබූ අතර, ඒවා ගොනුව තුළ සරලව මඟ හැර ඇත, මේ නිසා, මගේ නඩුවේදී ප්‍රතිසාධනය කිරීමට ව්‍යුහය තීරණය කිරීමට නොහැකි විය. නව තීරුවල, පෙරනිමි අගය ශුන්‍ය වූ අතර, innodb_flush_log_at_trx_commit = 0 සැකසීම හේතුවෙන් ගනුදෙනුවේ කොටසක් අහිමි විය හැක, එබැවින් ව්‍යුහය තීරණය කිරීමට අමතර කාලයක් වැය කිරීමට සිදුවේ.

ගැටලුව 2: DELETE හරහා මකා දැමූ පේළි සියල්ලම ibd ගොනුවේ ඇති බව සැලකිල්ලට ගත යුතුය, නමුත් ALTER TABLE සමඟ ඒවායේ ව්යුහය යාවත්කාලීන නොවේ. ප්රතිඵලයක් වශයෙන්, දත්ත ව්යුහය ගොනුවේ ආරම්භයේ සිට අවසානය දක්වා වෙනස් විය හැක. ඔබ බොහෝ විට OPTIMIZE TABLE භාවිතා කරන්නේ නම්, ඔබට එවැනි ගැටලුවකට මුහුණ දීමට අපහසුය.

අවධානය යොමු කරන්න, DBMS අනුවාදය දත්ත ගබඩා කරන ආකාරය කෙරෙහි බලපාන අතර, මෙම උදාහරණය අනෙකුත් ප්‍රධාන අනුවාද සඳහා ක්‍රියා නොකරනු ඇත. මගේ නඩුවේදී, mariadb 10.1.24 හි windows අනුවාදය භාවිතා කරන ලදී. එසේම, mariadb හි ඔබ InnoDB වගු සමඟ වැඩ කළත්, ඇත්ත වශයෙන්ම ඒවා වේ XtraDB, InnoDB mysql සමඟ ක්‍රමයේ අදාළත්වය බැහැර කරයි.

ගොනු විශ්ලේෂණය

python හි, දත්ත වර්ගය බයිට්() සාමාන්‍ය සංඛ්‍යා කට්ටලයක් වෙනුවට යුනිකෝඩ් දත්ත පෙන්වයි. ඔබට මෙම පෝරමයේ ගොනුව බැලිය හැකි වුවද, පහසුව සඳහා බයිට් අරාව සාමාන්‍ය අරාවක් (list(example_byte_array)) බවට පරිවර්තනය කිරීමෙන් ඔබට බයිට් සංඛ්‍යාත්මක ආකාරයෙන් පරිවර්තනය කළ හැක. ඕනෑම අවස්ථාවක, ක්රම දෙකම විශ්ලේෂණය සඳහා සුදුසු වේ.

ibd ගොනු කිහිපයක් බැලීමෙන් පසු, ඔබට පහත සඳහන් දෑ සොයාගත හැකිය:

ibd ගොනුවේ byte-by-byte විශ්ලේෂණය භාවිතයෙන් ව්‍යුහ ගොනුවක් නොමැතිව XtraDB වගු වලින් දත්ත ප්‍රතිසාධනය කිරීම

එපමණක් නොව, ඔබ මෙම මූල පද වලින් ගොනුව බෙදුවහොත්, ඔබට බොහෝ දුරට දත්ත අවහිර කිරීම් පවා ලැබෙනු ඇත. අපි infimum භාජකයක් ලෙස භාවිතා කරන්නෙමු.

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

සිත්ගන්නාසුලු නිරීක්ෂණයක්: දත්ත කුඩා ප්‍රමාණයක් සහිත වගු සඳහා, infimum සහ supremum අතර බ්ලොක් එකේ පේළි ගණනට දර්ශකයක් ඇත.

ibd ගොනුවේ byte-by-byte විශ්ලේෂණය භාවිතයෙන් ව්‍යුහ ගොනුවක් නොමැතිව XtraDB වගු වලින් දත්ත ප්‍රතිසාධනය කිරීම - 1 වන පේළිය සහිත පරීක්ෂණ වගුව

ibd ගොනුවේ byte-by-byte විශ්ලේෂණය භාවිතයෙන් ව්‍යුහ ගොනුවක් නොමැතිව XtraDB වගු වලින් දත්ත ප්‍රතිසාධනය කිරීම - පේළි 2 ක් සහිත පරීක්ෂණ වගුව

පේළි අරා වගුව[0] මඟ හැරිය හැක. ඒක බැලුවට පස්සෙත් තාම raw table data හොයාගන්න බැරි උනා. බොහෝ දුරට ඉඩ, මෙම බ්ලොක් දර්ශක සහ යතුරු ගබඩා කිරීම සඳහා භාවිතා වේ.
වගුව [1] සමඟින් ආරම්භ කර එය සංඛ්‍යාත්මක අරාවකට පරිවර්තනය කිරීමෙන්, ඔබට දැනටමත් සමහර රටා දැකිය හැක, එනම්:

ibd ගොනුවේ byte-by-byte විශ්ලේෂණය භාවිතයෙන් ව්‍යුහ ගොනුවක් නොමැතිව XtraDB වගු වලින් දත්ත ප්‍රතිසාධනය කිරීම

මේවා තන්තුවක ගබඩා කර ඇති int අගයන් වේ. පළමු බයිටයෙන් අංකය ධන හෝ ඍණ ද යන්න පෙන්නුම් කරයි. මගේ නඩුවේදී, සියලුම සංඛ්යා ධනාත්මක වේ. ඉතිරි බයිට් 3 න්, ඔබට පහත ශ්‍රිතය භාවිතයෙන් අංකය තීරණය කළ හැක. පිටපත:

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

උදාහරණයක් ලෙස, 128, 0, 0, 1 = 1, හෝ 128, 0, 75, 108 = 19308.
මේසයේ ස්වයංක්‍රීය වර්ධක සහිත ප්‍රාථමික යතුරක් තිබී ඇති අතර එය මෙහි ද සොයා ගත හැක

ibd ගොනුවේ byte-by-byte විශ්ලේෂණය භාවිතයෙන් ව්‍යුහ ගොනුවක් නොමැතිව XtraDB වගු වලින් දත්ත ප්‍රතිසාධනය කිරීම

පරීක්ෂණ වගු වලින් දත්ත සංසන්දනය කිරීමෙන් පසුව, DATETIME වස්තුව බයිට් 5 කින් සමන්විත වන අතර 153 කින් ආරම්භ වන බව අනාවරණය විය (බොහෝ විට වාර්ෂික කාල පරතරයන් දක්වයි). DATTIME පරාසය '1000-01-01' සිට '9999-12-31' දක්වා වන බැවින්, මම හිතන්නේ බයිට් ගණන වෙනස් විය හැකි නමුත්, මගේ නඩුවේදී, දත්ත 2016 සිට 2019 දක්වා කාල සීමාව තුළ වැටේ, එබැවින් අපි උපකල්පනය කරමු බයිට් 5ක් ප්‍රමාණවත් බව.

තත්පර නොමැතිව කාලය තීරණය කිරීම සඳහා, පහත සඳහන් කාර්යයන් ලියා ඇත. පිටපත:

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}

අවුරුද්දට මාසයට ක්‍රියාකාරී ශ්‍රිතයක් ලිවීමට නොහැකි වූ නිසා මට එය හැක් කිරීමට සිදු විය. පිටපත:

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

ඔබ කාලය ගත කරන්නේ නම්, මෙම වැරදි වැටහීම නිවැරදි කළ හැකි බව මට විශ්වාසයි.
ඊළඟට, තන්තුවකින් දිනකාල වස්තුවක් ආපසු ලබා දෙන ශ්‍රිතයක්. පිටපත:

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)

int, int, datetime, datetime වලින් නිතර නිතර පුනරාවර්තන අගයන් හඳුනා ගැනීමට කළමනාකරණය කර ඇත ibd ගොනුවේ byte-by-byte විශ්ලේෂණය භාවිතයෙන් ව්‍යුහ ගොනුවක් නොමැතිව XtraDB වගු වලින් දත්ත ප්‍රතිසාධනය කිරීම, ඔබට අවශ්‍ය වන්නේ මෙය බව පෙනේ. එපමණක් නොව, එවැනි අනුපිළිවෙලක් පේළියකට දෙවරක් නැවත නැවතත් නොකෙරේ.

සාමාන්‍ය ප්‍රකාශනයක් භාවිතා කරමින්, අපි අවශ්‍ය දත්ත සොයා ගනිමු:

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)

මෙම ප්‍රකාශනය භාවිතා කරමින් සෙවීමේදී, අවශ්‍ය ක්ෂේත්‍රවල NULL අගයන් තීරණය කිරීමට නොහැකි වනු ඇති බව කරුණාවෙන් සලකන්න, නමුත් මගේ නඩුවේදී මෙය තීරණාත්මක නොවේ. ඊට පස්සේ අපි ලූප් එකකින් හොයාගත්ත දේ හරහා යනවා. පිටපත:

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)

ඇත්ත වශයෙන්ම, එපමණයි, ප්රතිඵල අරාවේ දත්ත අපට අවශ්ය දත්ත වේ. ###PS.###
මෙම ක්‍රමය සෑම කෙනෙකුටම සුදුසු නොවන බව මට වැටහේ, නමුත් ලිපියේ ප්‍රධාන අරමුණ වන්නේ ඔබේ සියලු ගැටලු විසඳීමට වඩා ඉක්මන් ක්‍රියාමාර්ගයක් ගැනීමයි. මම හිතන්නේ වඩාත්ම නිවැරදි විසඳුම වනුයේ මූල කේතය ඔබම අධ්‍යයනය කිරීම ආරම්භ කිරීමයි මාරියාඩ්බ්, නමුත් සීමිත කාලය නිසා, වත්මන් ක්රමය වේගවත්ම බව පෙනෙන්නට තිබුණි.

සමහර අවස්ථාවලදී, ගොනුව විශ්ලේෂණය කිරීමෙන් පසු, ඔබට ආසන්න ව්යුහය තීරණය කිරීමට සහ ඉහත සබැඳි වලින් සම්මත ක්රම වලින් එකක් භාවිතා කර එය ප්රතිෂ්ඨාපනය කිරීමට ඔබට හැකි වනු ඇත. මෙය වඩාත් නිවැරදි වන අතර අඩු ගැටළු ඇති කරයි.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න