
முன்வரலாறு
சர்வர் ஒரு ransomware வைரஸால் தாக்கப்பட்டது, இது ஒரு "அதிர்ஷ்டவசமான விபத்தால்", .ibd கோப்புகளை (innodb அட்டவணைகளின் மூல தரவு கோப்புகள்) பகுதியளவு தொடாமல் விட்டுவிட்டது, ஆனால் அதே நேரத்தில் .fpm கோப்புகளை முழுவதுமாக என்க்ரிப்ட் செய்தது ( கட்டமைப்பு கோப்புகள்). இந்த வழக்கில், .idb ஐ பின்வருமாறு பிரிக்கலாம்:
- நிலையான கருவிகள் மற்றும் வழிகாட்டிகள் மூலம் மறுசீரமைப்புக்கு உட்பட்டது. அத்தகைய சந்தர்ப்பங்களில், ஒரு சிறந்த உள்ளது ;
- பகுதி மறைகுறியாக்கப்பட்ட அட்டவணைகள். பெரும்பாலும் இவை பெரிய அட்டவணைகளாகும், அதற்காக (நான் புரிந்து கொண்டபடி) தாக்குபவர்களிடம் முழு குறியாக்கத்திற்கு போதுமான ரேம் இல்லை;
- சரி, முழுமையாக மறைகுறியாக்கப்பட்ட அட்டவணைகளை மீட்டெடுக்க முடியாது.
விரும்பிய குறியாக்கத்தின் கீழ் எந்த உரை எடிட்டரிலும் அதைத் திறப்பதன் மூலம் அட்டவணைகள் எந்த விருப்பத்தைச் சேர்ந்தவை என்பதை தீர்மானிக்க முடிந்தது (என் விஷயத்தில் இது UTF8) மற்றும் உரை புலங்களின் இருப்புக்கான கோப்பைப் பார்ப்பது, எடுத்துக்காட்டாக:

மேலும், கோப்பின் தொடக்கத்தில் நீங்கள் அதிக எண்ணிக்கையிலான 0 பைட்டுகளை அவதானிக்கலாம், மேலும் பிளாக் என்க்ரிப்ஷன் அல்காரிதம் (மிகவும் பொதுவானது) பயன்படுத்தும் வைரஸ்கள் பொதுவாக அவற்றையும் பாதிக்கும்.
![]()
என் விஷயத்தில், தாக்குபவர்கள் ஒவ்வொரு மறைகுறியாக்கப்பட்ட கோப்பின் முடிவிலும் 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_pointint(11);id_userint(11);date_startதேதி நேரம்;date_finishதேதி நேரம்.
மீட்டெடுப்பதற்கு, .ibd கோப்பின் பைட்-பை-பைட் பகுப்பாய்வு பயன்படுத்தப்படுகிறது, அதைத் தொடர்ந்து அவற்றை மேலும் படிக்கக்கூடிய வடிவமாக மாற்றுகிறது. நமக்குத் தேவையானதைக் கண்டுபிடிப்பதற்கு, எண்ணு மற்றும் டேட்டாடைம் போன்ற தரவு வகைகளை மட்டுமே நாம் பகுப்பாய்வு செய்ய வேண்டும், கட்டுரை அவற்றை மட்டுமே விவரிக்கும், ஆனால் சில சமயங்களில் நாங்கள் மற்ற தரவு வகைகளையும் குறிப்பிடுவோம், இது மற்ற ஒத்த சம்பவங்களுக்கு உதவும்.
பிரச்சனை 1: DATETIME மற்றும் TEXT வகைகளைக் கொண்ட புலங்கள் NULL மதிப்புகளைக் கொண்டிருந்தன, மேலும் அவை கோப்பில் தவிர்க்கப்படுகின்றன, இதன் காரணமாக, எனது விஷயத்தில் மீட்டமைப்பதற்கான கட்டமைப்பைத் தீர்மானிக்க முடியவில்லை. புதிய நெடுவரிசைகளில், இயல்புநிலை மதிப்பு பூஜ்யமாக இருந்தது, மேலும் innodb_flush_log_at_trx_commit = 0 அமைப்பால் பரிவர்த்தனையின் ஒரு பகுதியை இழக்க நேரிடும், எனவே கட்டமைப்பைத் தீர்மானிக்க கூடுதல் நேரம் செலவிட வேண்டியிருக்கும்.
பிரச்சனை 2: DELETE மூலம் நீக்கப்பட்ட வரிசைகள் அனைத்தும் ibd கோப்பில் இருக்கும் என்பதை கணக்கில் எடுத்துக்கொள்ள வேண்டும், ஆனால் ALTER TABLE மூலம் அவற்றின் அமைப்பு புதுப்பிக்கப்படாது. இதன் விளைவாக, தரவு அமைப்பு கோப்பின் தொடக்கத்திலிருந்து அதன் இறுதி வரை மாறுபடும். நீங்கள் அடிக்கடி OPTIMIZE TABLE ஐப் பயன்படுத்தினால், அத்தகைய சிக்கலை நீங்கள் சந்திக்க வாய்ப்பில்லை.
கவனம் செலுத்துங்கள், DBMS பதிப்பு தரவு சேமிக்கப்படும் முறையை பாதிக்கிறது, மேலும் இந்த உதாரணம் மற்ற முக்கிய பதிப்புகளுக்கு வேலை செய்யாமல் போகலாம். என் விஷயத்தில், mariadb 10.1.24 இன் விண்டோஸ் பதிப்பு பயன்படுத்தப்பட்டது. மேலும், mariadb இல் நீங்கள் InnoDB அட்டவணைகளுடன் பணிபுரிந்தாலும், உண்மையில் அவை , இது InnoDB mysql உடன் முறையின் பொருந்தக்கூடிய தன்மையை விலக்குகிறது.
கோப்பு பகுப்பாய்வு
பைத்தானில், தரவு வகை வழக்கமான எண்களின் தொகுப்பிற்குப் பதிலாக யூனிகோட் தரவைக் காட்டுகிறது. இந்தப் படிவத்தில் கோப்பைப் பார்க்க முடியும் என்றாலும், வசதிக்காக பைட் வரிசையை வழக்கமான வரிசையாக மாற்றுவதன் மூலம் பைட்டுகளை எண் வடிவமாக மாற்றலாம் (list(example_byte_array)). எந்தவொரு சந்தர்ப்பத்திலும், இரண்டு முறைகளும் பகுப்பாய்வுக்கு ஏற்றது.
பல ibd கோப்புகளைப் பார்த்த பிறகு, பின்வருவனவற்றைக் காணலாம்:
![]()
மேலும், இந்த முக்கிய வார்த்தைகளால் கோப்பைப் பிரித்தால், நீங்கள் பெரும்பாலும் தரவுத் தொகுதிகளைப் பெறுவீர்கள். நாம் infimum ஐ வகுப்பியாகப் பயன்படுத்துவோம்.
table = table.split("infimum".encode())ஒரு சுவாரசியமான அவதானிப்பு: சிறிய அளவிலான தரவுகளைக் கொண்ட அட்டவணைகளுக்கு, இன்ஃபிமம் மற்றும் சுப்ரீம் இடையே, தொகுதியில் உள்ள வரிசைகளின் எண்ணிக்கைக்கு ஒரு சுட்டிக்காட்டி உள்ளது.
- 1 வது வரிசையுடன் சோதனை அட்டவணை
- 2 வரிசைகள் கொண்ட சோதனை அட்டவணை
வரிசை வரிசை அட்டவணை[0] தவிர்க்கப்படலாம். அதைப் பார்த்த பிறகும் என்னால் ரா டேபிள் டேட்டாவைக் கண்டுபிடிக்க முடியவில்லை. பெரும்பாலும், இந்த தொகுதி குறியீடுகள் மற்றும் விசைகளை சேமிக்க பயன்படுத்தப்படுகிறது.
அட்டவணையில்[1] தொடங்கி, அதை ஒரு எண் வரிசையில் மொழிபெயர்த்தால், நீங்கள் ஏற்கனவே சில வடிவங்களைக் கவனிக்கலாம், அதாவது:

இவை ஒரு சரத்தில் சேமிக்கப்பட்ட முழு எண் மதிப்புகள். முதல் பைட் எண் நேர்மறை அல்லது எதிர்மறை என்பதைக் குறிக்கிறது. என் விஷயத்தில், எல்லா எண்களும் நேர்மறை. மீதமுள்ள 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.
அட்டவணையில் தானியங்கு அதிகரிப்புடன் கூடிய முதன்மை விசை இருந்தது, அதை இங்கேயும் காணலாம்

சோதனை அட்டவணையில் இருந்து தரவை ஒப்பிட்டுப் பார்த்ததில், 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 ஆகியவற்றிலிருந்து அடிக்கடி திரும்பத் திரும்ப வரும் மதிப்புகளைக் கண்டறிய நிர்வகிக்கப்படுகிறது
, இது உங்களுக்குத் தேவையானது போல் தெரிகிறது. மேலும், அத்தகைய வரிசை ஒரு வரிக்கு இரண்டு முறை மீண்டும் செய்யப்படுவதில்லை.
வழக்கமான வெளிப்பாட்டைப் பயன்படுத்தி, தேவையான தரவைக் காண்கிறோம்:
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
