ibd файлын байт-байт шинжилгээг ашиглан бүтцийн файлгүйгээр XtraDB хүснэгтүүдээс өгөгдлийг сэргээх

ibd файлын байт-байт шинжилгээг ашиглан бүтцийн файлгүйгээр XtraDB хүснэгтүүдээс өгөгдлийг сэргээх

Эрьт урьдын түүх

Сервер ransomware вирусын халдлагад өртөж, "азтай ослоор" .ibd файлуудыг (innodb хүснэгтүүдийн түүхий өгөгдлийн файлууд) хэсэгчлэн орхисон боловч .fpm файлуудыг бүрэн шифрлэсэн (). бүтцийн файлууд). Энэ тохиолдолд .idb-г дараахь байдлаар хувааж болно.

  • стандарт багаж хэрэгсэл, хөтөчөөр дамжуулан сэргээн засварлах ёстой. Ийм тохиолдлын хувьд маш сайн байдаг болох;
  • хэсэгчлэн шифрлэгдсэн хүснэгтүүд. Ихэнхдээ эдгээр нь том хүснэгтүүд бөгөөд (миний ойлгож байгаагаар) халдагчдад бүрэн шифрлэхэд хангалттай RAM байхгүй байсан;
  • За, сэргээх боломжгүй бүрэн шифрлэгдсэн хүснэгтүүд.

Хүссэн кодчилолоор (миний хувьд энэ нь UTF8) ямар ч текст засварлагч дээр нээж, текст талбар байгаа эсэхийг зүгээр л үзэх замаар хүснэгтүүд аль сонголтод хамаарахыг тодорхойлох боломжтой байсан, жишээлбэл:

ibd файлын байт-байт шинжилгээг ашиглан бүтцийн файлгүйгээр XtraDB хүснэгтүүдээс өгөгдлийг сэргээх

Мөн файлын эхэнд та маш олон тооны 0 байтыг ажиглаж болох бөгөөд блок шифрлэлтийн алгоритмыг ашигладаг вирусууд (хамгийн түгээмэл) ихэвчлэн тэдэнд нөлөөлдөг.
ibd файлын байт-байт шинжилгээг ашиглан бүтцийн файлгүйгээр 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 файлын байт-байт шинжилгээг ашиглан тэдгээрийг илүү унших боломжтой хэлбэрт хөрвүүлнэ. Бидэнд хэрэгтэй зүйлээ олохын тулд зөвхөн 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-д хэрэглэх боломжийг үгүйсгэдэг.

Файлын шинжилгээ

Питон хэл дээр өгөгдлийн төрөл байт() ердийн багц тоонуудын оронд Юникод өгөгдлийг харуулдаг. Хэдийгээр та энэ хэлбэрээр файлыг үзэх боломжтой боловч тав тухтай байлгах үүднээс байт массивыг ердийн массив болгон хөрвүүлэх замаар байтыг тоон хэлбэрт хөрвүүлж болно (жагсаалт(жишээ нь_байт_массив)). Ямар ч тохиолдолд хоёр арга хоёулаа дүн шинжилгээ хийхэд тохиромжтой.

Хэд хэдэн ibd файлуудыг үзсэний дараа та дараахь зүйлийг олж болно.

ibd файлын байт-байт шинжилгээг ашиглан бүтцийн файлгүйгээр XtraDB хүснэгтүүдээс өгөгдлийг сэргээх

Түүнээс гадна, хэрэв та эдгээр түлхүүр үгсээр файлыг хуваах юм бол та ихэнхдээ нэг блок өгөгдөл авах болно. Бид инфимумыг хуваагч болгон ашиглах болно.

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

Сонирхолтой ажиглалт: бага хэмжээний өгөгдөл бүхий хүснэгтүүдийн хувьд infimum болон supremum хооронд блок дахь мөрийн тоог заагч байдаг.

ibd файлын байт-байт шинжилгээг ашиглан бүтцийн файлгүйгээр XtraDB хүснэгтүүдээс өгөгдлийг сэргээх - 1-р эгнээ бүхий туршилтын хүснэгт

ibd файлын байт-байт шинжилгээг ашиглан бүтцийн файлгүйгээр XtraDB хүснэгтүүдээс өгөгдлийг сэргээх - 2 эгнээ бүхий туршилтын хүснэгт

Мөрийн массив хүснэгтийг[0] алгасаж болно. Үүнийг харсны дараа би хүснэгтийн түүхий өгөгдлийг олж чадаагүй хэвээр байв. Магадгүй энэ блок нь индекс, түлхүүрүүдийг хадгалахад ашиглагддаг.
Хүснэгт[1]-ээс эхлээд тоон массив руу хөрвүүлснээр та зарим хэв маягийг аль хэдийн анзаарч болно, тухайлбал:

ibd файлын байт-байт шинжилгээг ашиглан бүтцийн файлгүйгээр 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 файлын байт-байт шинжилгээг ашиглан бүтцийн файлгүйгээр 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

Хэрэв та маш их цаг зарцуулбал энэ үл ойлголцлыг засах боломжтой гэдэгт би итгэлтэй байна.
Дараа нь мөрөөс datetime объектыг буцаадаг функц. Скрипт:

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 файлын байт-байт шинжилгээг ашиглан бүтцийн файлгүйгээр 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)

Үнэндээ энэ бол үр дүнгийн массивын өгөгдөл нь бидэнд хэрэгтэй өгөгдөл юм. ###Жич.###
Энэ арга нь хүн бүрт тохиромжгүй гэдгийг би ойлгож байна, гэхдээ нийтлэлийн гол зорилго нь таны бүх асуудлыг шийдэхээс илүүтэйгээр яаралтай арга хэмжээ авах явдал юм. Би өөрөө эх кодыг судалж эхлэх нь хамгийн зөв шийдэл гэж бодож байна mariadb, гэхдээ цаг хугацаа хязгаарлагдмал байсан тул одоогийн арга нь хамгийн хурдан нь юм шиг санагдсан.

Зарим тохиолдолд файлд дүн шинжилгээ хийсний дараа та ойролцоо бүтцийг тодорхойлж, дээрх холбоосуудаас стандарт аргуудын аль нэгийг ашиглан сэргээх боломжтой болно. Энэ нь илүү зөв бөгөөд бага асуудал үүсгэх болно.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх