Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 2 сентября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь


Взлом трёх виртуальных машин (crackme с VM), часть 1




Очень удобно, когда все крэкерские инструменты, книги и статьи в одном месте. Используйте сборник от EXELAB - вот тут.



CrackMe #0 by Olenevod:

Исследование и декомпиляция.



Автор: ev1l^4

# Вступление #


Эта статья про взлом crackme от Olenevod, основной защитой является VM. CrackMe написан достаточно интересно, снаружи фейковая проверка, которая в общем-то и нерешаема, а спрятана, если так можно выразиться, достаточно интересно выраженная. Спрятанный код перехватывает некоторые API - записывает переход на интерпретатор, который исполняет проверку серийного номера.



# Обзор Crackme и VM #


 			0041E376 			 - E9 7D3AFEFF     JMP 00401DF8                             ; 			CrackMe.00401DF8
 			

Переход на процедуру инициализации данных и перехват функций в stub UPX.


 			0040143D 			   C705 1C104000 0>MOV DWORD PTR [40101C], 1
 			00401447 			   FF35 08414000   PUSH DWORD PTR [404108]
 			0040144D 			   E8 9E010000     CALL 004015F0                            ; 			CrackMe.004015F0
 			

Инициализация переменной, определяющей интерпретатору путь интерпретации. Получение строки имени.


 			0040145F 			   C705 1C104000 0>MOV DWORD PTR [40101C], 2
 			00401469 			   FF35 0C414000   PUSH DWORD PTR [40410C]
 			0040146F 			   E8 7C010000     CALL 004015F0                            ; 			CrackMe.004015F0
 			

Аналогично. Получение строки серийного номера.


 			004014A3 			   8B0D 24104000   MOV ECX, DWORD PTR [401024]
 			004014A9 			   83C1 04         ADD ECX, 4
 			004014AC 			   50              PUSH EAX
 			004014AD 			   8D45 F0         LEA EAX, DWORD PTR [EBP-10]
 			004014B0 			   50              PUSH EAX
 			004014B1 			   51              PUSH ECX
 			004014B2 			   E8 99000000     CALL 00401550                            ; 			CrackMe.00401550
 		 	  // Перевод символов в шестнадцатеричные цифры.
 
004014DB E8 30070000 CALL 00401C10 ; CrackMe.00401C10 004014E0 6A 10 PUSH 10 004014E2 57 PUSH EDI ; ntdll.7C910738 004014E3 E8 68070000 CALL 00401C50 ; CrackMe.00401C50 004014E8 E8 C3070000 CALL 00401CB0 ; CrackMe.00401CB0 //Процедуры MD5 хэш-алгоритма.
004015F0 55 PUSH EBP 004015F1 8BEC MOV EBP, ESP 004015F3 83C4 FC ADD ESP, -4 004015F6 33C0 XOR EAX, EAX 004015F8 60 PUSHAD 004015F9 FF75 08 PUSH DWORD PTR [EBP+8] 004015FC E8 D1090000 CALL 00401FD2 ; JMP to USER32.GetWindowTextLengthA 00401601 0BC0 OR EAX, EAX 00401603 74 2B JE SHORT 00401630 00401605 8BF8 MOV EDI, EAX 00401607 83C0 05 ADD EAX, 5 0040160A 50 PUSH EAX 0040160B 6A 40 PUSH 40 0040160D E8 080A0000 CALL 0040201A ; JMP to kernel32.GlobalAlloc 00401612 8945 FC MOV DWORD PTR [EBP-4], EAX 00401615 0BC0 OR EAX, EAX 00401617 74 17 JE SHORT 00401630 00401619 8938 MOV DWORD PTR [EAX], EDI 0040161B 83C0 04 ADD EAX, 4 0040161E 47 INC EDI 0040161F 57 PUSH EDI 00401620 50 PUSH EAX 00401621 FF75 08 PUSH DWORD PTR [EBP+8] 00401624 E8 A3090000 CALL 00401FCC ; JMP to USER32.GetWindowTextA 00401629 8B45 FC MOV EAX, DWORD PTR [EBP-4] 0040162C 894424 1C MOV DWORD PTR [ESP+1C], EAX 00401630 61 POPAD 00401631 C9 LEAVE 00401632 C2 0400 RETN 4

Функция получения строки имени и серийного номера. API GetWindowTextA перехвачена.


 			77D5F82E 			>  68 AC154000     PUSH 4015AC
 			77D5F833 			   C3              RETN
 		 	  // Код перехваченной функции GetWindowTextA.
 
004015AC 68 6790FFB3 PUSH B3FF9067 004015B1 FF25 28104000 JMP DWORD PTR [401028] ; CrackMe.0040593C

Вызов интерпретатора, значение B3FF9067 используется после инициализации VM и дешифровки этого значения для перехода.



 			0040593C 			   9C              PUSHFD
 			0040593D 			   50              PUSH EAX
 			0040593E 			   51              PUSH ECX
 			0040593F 			   52              PUSH EDX                                  			
 			00405940 			   8D4424 14       LEA EAX, DWORD PTR [ESP+14]
 			00405944 			   53              PUSH EBX
 			00405945 			   50              PUSH EAX
 			00405946 			   55              PUSH EBP
 			00405947 			   56              PUSH ESI
 			00405948 			   57              PUSH EDI                                  			
 			00405949 			   E8 00000000     CALL 0040594E                             			
 			0040594E 			   5E              POP ESI                                   			
 			0040594F 			   81EE CE144000   SUB ESI, 4014CE
 			00405955 			   6A 51           PUSH 51
 			00405957 			   6A 40           PUSH 40
 			00405959 			   B8 2DFF807C     MOV EAX, 7C80FF2D ; kernel32.GlobalAlloc
 			0040595E 			   FFD0            CALL EAX
 			00405960 			   8BF8            MOV EDI, EAX
 			00405962 			   8D86 16164000   LEA EAX, DWORD PTR [ESI+401616]
 			00405968 			   8907            MOV DWORD PTR [EDI], EAX
 			

Инициализация VM, выделение адреса для контекста VM. Инструкция по адресу 00405962 получает указатель на PCODE. Регистр EDI является указателем на адрес данных PCODE.


 			0040596A 			   8B07            MOV EAX, DWORD PTR [EDI]
 			0040596C 			   8A00            MOV AL, BYTE PTR [EAX]
 			0040596E 			   04 43           ADD AL, 43
 			00405970 			   34 19           XOR AL, 19
 			00405972 			   F6D0            NOT AL
 			00405974 			   34 4F           XOR AL, 4F
 			00405976 			   2C 69           SUB AL, 69
 			00405978 			   0FB6C0          MOVZX EAX, AL
 			0040597B 			   8307 01         ADD DWORD PTR [EDI], 1
 		 	  // Номер любой инструкции расшифровывается этим алгоритмом.
 
0040597E 8B8486 EF234000 MOV EAX, DWORD PTR [ESI+EAX*4+4023EF] 00405985 8D8430 CE144000 LEA EAX, DWORD PTR [EAX+ESI+4014CE] 0040598C - FFE0 JMP EAX // Вычисление адреса команды интерпретатора и переход на неё.

000000BB 0000001C FFFFFB32 00000133 000000F4 FFFFFC87 FFFFFD00 FFFFFF19 FFFFFF8D FFFFFDA3 FFFFFC06 FFFFFB66 FFFFFB93 FFFFFBC9 FFFFFE45 FFFFFEE3 00000040

Всего 17 значений для получения адреса команд, а значит и команд столько же.


 			00405A42 			   8B07            MOV EAX, DWORD PTR [EDI]
 			00405A44 			   8B00            MOV EAX, DWORD PTR [EAX]
 			00405A46 			   05 40264907     ADD EAX, 7492640
 			00405A4B 			   35 41115761     XOR EAX, 61571141
 			00405A50 			   F7D0            NOT EAX
 			00405A52 			   2D 4D8A9300     SUB EAX, 938A4D
 			00405A57 			   8307 04         ADD DWORD PTR [EDI], 4
 			00405A5A 			   8947 14         MOV DWORD PTR [EDI+14], EAX
 			00405A5D 			   8B07            MOV EAX, DWORD PTR [EDI]
 			00405A5F 			   8A00            MOV AL, BYTE PTR [EAX]
 			00405A61 			   04 43           ADD AL, 43
 			00405A63 			   34 19           XOR AL, 19
 			00405A65 			   F6D0            NOT AL
 			00405A67 			   34 4F           XOR AL, 4F
 			00405A69 			   2C 69           SUB AL, 69
 			00405A6B 			   0FB6C0          MOVZX EAX, AL
 			00405A6E 			   8307 01         ADD DWORD PTR [EDI], 1
 			00405A71 			   8B8486 EF234000 MOV EAX, DWORD PTR [ESI+EAX*4+4023EF]
 			00405A78 			   8D8430 CE144000 LEA EAX, DWORD PTR [EAX+ESI+4014CE]
 			00405A7F    			FFE0            JMP EAX
 		 	  
// В качестве примера, интерпретация команды MOV DWORD PTR [EDI+14], CONST
00405A81 57 PUSH EDI 00405A82 B8 2FFE807C MOV EAX, 7C80FE2F 00405A87 FFD0 CALL EAX 00405A89 9D POPFD 00405A8A 5F POP EDI 00405A8B 5E POP ESI 00405A8C 5D POP EBP 00405A8D 58 POP EAX 00405A8E 5B POP EBX 00405A8F 5A POP EDX 00405A90 59 POP ECX 00405A91 870424 XCHG DWORD PTR [ESP], EAX 00405A94 5C POP ESP 00405A95 C3 RETN

Команда EXIT, освобождает память контекста VM и инициализирует регистры процессора.



 			00405831 			   8B07            MOV EAX, DWORD PTR [EDI]
 			00405833 			   0FB600          MOVZX EAX, BYTE PTR [EAX]
 			00405836 			   2C 54           SUB AL, 54
 			00405838 			   34 24           XOR AL, 24
 			0040583A 			   F6D0            NOT AL
 			0040583C 			   34 6C           XOR AL, 6C
 			0040583E 			   8B0438          MOV EAX, DWORD PTR [EAX+EDI]
 			00405841 			   0107            ADD DWORD PTR [EDI], EAX
 			00405843 			   8B07            MOV EAX, DWORD PTR [EDI]
 			00405845 			   8A00            MOV AL, BYTE PTR [EAX]
 			00405847 			   04 43           ADD AL, 43
 			00405849 			   34 19           XOR AL, 19
 			0040584B 			   F6D0            NOT AL
 			0040584D 			   34 4F           XOR AL, 4F
 			0040584F 			   2C 69           SUB AL, 69
 			00405851 			   0FB6C0          MOVZX EAX, AL
 			00405854 			   8307 01         ADD DWORD PTR [EDI], 1
 			00405857 			   8B8486 EF234000 MOV EAX, DWORD PTR [ESI+EAX*4+4023EF]
 			0040585E 			   8D8430 CE144000 LEA EAX, DWORD PTR [EAX+ESI+4014CE]
 			00405865 			   FFE0            JMP EAX
 			

Команда перехода, самое сложное в данной VM, т.к. переход вычисляется динамически.





# Декомпиляция VM #


Перед декомпиляцией данную VM лучше упростить, а именно лишить её динамического вычисления адреса команды. См. Small_VM_Olenevod. Можно писать декомпилятор, для этого нужно определить буфер для декомпилированного кода, буфер для индекса и смещения каждой команды или блока команд, чтобы можно было совершать переход.


 			; 			Initialization
 			mov 			[pDeVMcode], offset DeVMcode ; DECOMPILE CODE
 			mov 			[pdbPCODE], offset dbPCODE ; PCODE
 			mov 			[pVMINDX], offset VMINDX ; INDEX & ADDRESS
 			
mov edi, offset pdbPCODE xor eax, eax inc eax .repeat call DECOMPILE_PROC mov ecx, dword ptr [edi] mov ecx, dword ptr [ecx] .until eax > 16 && (!ecx)

Инициализация указателей и основной цикл декомпилятора, который содержит функцию для восстановления команд и определяет конец PCODE.




 			DECOMPILE_PROC 			proc
 			; 			Init index and address
 			.if 			eax >= 0 && eax <= 16
 			pushad
 			mov 			edi, [pVMINDX]
 			mov 			eax, dword ptr [pdbPCODE]
 			sub 			eax, offset dbPCODE
 			stosd
 			mov 			eax, [pDeVMcode]
 			sub 			eax, offset DeVMcode
 			stosd
 			mov 			[pVMINDX], edi
 			popad
 			.endif
 			

Сохранение индекса PCODE команды и декомпилированной команды. Также этот код проверяет значение команды, т.к. среди псевдо-кода содержится мусор, по крайней мере для интерпретатора.


 				;************************** 			- 15
 				pushad
 				mov 			edi, [pDeVMcode]
 				mov 			ecx, eax
 				mov 			ax, 878Bh ; MOV EAX, DWORD PTR [EDI+XXXXXXXX]
 				stosw
 				mov 			eax, ecx
 				stosd
 				mov 			al, 5h
 				stosb
 				mov 			eax, edx
 				stosd
 				mov 			eax, 0FC24548Bh
 				stosd
 				mov 			ax, 15FFh
 				stosw
 				mov 			eax, offset pGetAddress
 				stosd
 				mov 			eax, 0FC245489h
 				stosd
 				mov 			ax, 0E0FFh
 				stosw
 				mov 			[pDeVMcode], edi
 				popad
 				;**************************
 		 	  
//Декомпиляция перехода. MOV EAX, DWORD PTR [EDI+4] ADD EAX, 85 MOV EDX, DWORD PTR [ESP-4] CALL DWORD PTR [402E20] ; VM.004019E7 MOV DWORD PTR [ESP-4], EDX JMP EAX ;**************************

Код перехода от декомпилятора. Значение DWORD PTR [ESP-4] сохраняется для того, чтобы не затереть важные данные для интерпретатора.


 			GetAddress 			proc
 			mov 			ecx, offset VMINDX-8
 			.repeat
 			add 			ecx, 8
 			cmp 			dword ptr [ecx], eax
 			.until 			zero?
 			mov 			eax, dword ptr [ecx+4]
 			add 			eax, offset DeVMcode
 			retn
 			GetAddress 			EndP
 			

Процедура, которую вызывает инструкция CALL DWORD PTR [402E20]. Она ищет индекс PCODE и получает смещение для того, чтобы вычислить адрес для перехода.


Всё остальное можно узнать из исходников Decompile_VM_Olenevod.

Полученный код импортируется в CrackMe для дальнейшего исследования. См. CrackMe_u.exe.




# Упрощенный crackme #


 						invoke	GetDlgItemText,hWin,IDC_NAME,addr 			szName,sizeof szName
 						.if 			eax
 						mov 			esi, eax
 						invoke	GetDlgItemText,hWin,IDC_SERIAL,addr 			szSerial,sizeof szSerial
 						.if 			eax == 16
 						invoke 			CharToHex, addr Serial, addr szSerial, eax
 						invoke 			MD5Init
 						invoke 			MD5Update, addr szName, esi
 						invoke 			MD5Final
 						mov 			edx, dword ptr [eax+8]
 						xor 			edx, 0A7F527BBh
 						add 			edx, 783256h
 						xor 			edx, 9E15FCDEh
 						mov 			cl, byte ptr [eax]
 						ror 			edx, cl
 						mov 			cl, byte ptr [eax+1]
 						rol 			edx, cl
 						mov 			cl, byte ptr [eax+2]
 						ror 			edx, cl
 						mov 			cl, byte ptr [eax+3]
 						rol 			edx, cl
 						xor 			edx, dword ptr [Serial]
 						.if 			zero?
 						mov 			edx, dword ptr [eax+4]
 						rol 			edx, 11
 						add 			edx, 9E15FCDEh
 						add 			edx, dword ptr [eax+12]
 						xor 			edx, dword ptr [Serial+4]
 						.if 			zero?
 						push 			MB_OK
 						call 			@f
 						db 			"CrackMe",0
 						@@:
 						call 			@f
 						db 			"Congratulations! Serial is valid",0
 						@@:
 						push 			hWin
 						call 			MessageBox
 						.endif
 						.endif
 						.endif
 						.endif
 			

Проверка серийного номера. Значения из хэша модифицируются и командой XOR с значениями от серийного номера обнуляются для вызова сообщения.

# Заключение #


В заключении хотелось бы поблагодарить автора за такой замечательный CrackMe, а именно его общее выражение. Правда алгоритм проверки серийного номера оказался весьма простым, но интерпретатор достаточно интересным.


# Приложение #


#Crackme_Olenevod.zip – Оригинальный crackme и распакованный с импортированным декомпилированным кодом.

#Small_VM_Olenevod.zip – Упрощённая VM.

#Decompile_VM_Olenevod.zip – Декомпилятор VM.

#crackme.zip – Упрощённый crackme.

#keygen.zip – Keygen для crackme.



Скачать статью "Взлом трёх виртуальных машин (crackme с VM), часть 1" в авторском оформление + файлы.
пароль архива на картинке



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS