Trao đổi với tôi

http://www.buidao.com

6/29/09

[Reverse] Programming Anti-Cracking

Programming Anti-Cracking (Part 1)

Author: Benina (2008)

Tôi thuộc dạng newbie chính hiệu. Tất cả các bài viết của tôi đều thích hợp cho các bạn mới bắt đầu đọc. Bài viết này cũng ko ngọai lệ. Trong bài viết này tôi chỉ muốn cho các bạn newbie biết cách đơn giản nhất mà các coder coding Anti Crack. Từ đó chúng ta sẽ học nâng cao hơn trong các chủ đề sau này.

1/-Anti Set breakpoint on API function:

Một ví dụ để chứng minh việc ko cần import hàm API MessageBox nhưng vẫn sử dụng được hàm API này. Mục đích chính là để tránh các cracker set breakpoint trên hàm API để crack.

Phương pháp đầu tiên tui mới giới thiệu là dùng hàm LoadLibrary và GetProcAddress

.386

.model flat, stdcall

option casemap:none

include \masm32\include\windows.inc

include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib

.data

dwMessageBox dd 0

szUser32 db "USER32.dll",0

szMessageBox db "MessageBoxA",0

szTitle db 'No import func',0

szMessage db 'Show MessageBox but no import it!',0

.code

start:

invoke LoadLibrary,addr szUser32

invoke GetProcAddress,eax,offset szMessageBox

mov dwMessageBox,eax

push MB_OK

lea eax,szTitle

push eax

lea eax,szMessage

push eax

push 0

call dword ptr [dwMessageBox]

invoke ExitProcess,NULL

end start

2/-Anti Search for All referenced text strings:

Các cracker dùng tính năng search for all referenced text strings của debug để tìm addr của chuổi thông báo invalid key (bad boy). Do đó để ko để lộ string, chúng ta phải mã hóa (encrypt) nó trước tiên. Sau đó khi cần dùng string chúng ta decrypt lại string.

Sau đây là func vừa encrypt vừa decrypt chuổi string. Hàm này tui tham khảo trong code yC12 của yoda:

EnDeCryptString proc pAddressString:DWORD

PUSH ESI

PUSH EDI

MOV EAX,pAddressString

MOV ESI,EAX

MOV EDI,EAX

DllCryptLoop:

LODSB

ROR AL,4

STOSB

CMP BYTE PTR [EDI],0

JNZ DllCryptLoop

POP EDI

POP ESI

RET

EnDeCryptString endp

;--------------------------------------------------------------------------------------------------

Đây là tòan bộ code ví dụ. Tui ko giải thích nhiều ở đây. Tui chỉ nói sơ qua về cách tìm chuổi szMessage đã mã hóa như phần khai báo .data trong ví dụ. Tôi đã coding một chương trình encrypt chuổi ‘Show MessageBox but no import it!’. Rồi dùng Olly và plugin DataRipper để copy data chuổi đã mã hóa và past vào ví dụ của chúng ta.

.386

.model flat, stdcall

option casemap:none

include \masm32\include\windows.inc

include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib

EnDeCryptString PROTO :DWORD

.data

dwMessageBox dd 0

szUser32 db "USER32.dll",0

szMessageBox db "MessageBoxA",0

szTitle db 'Cryted String',0

szMessage db 035h, 086h, 0F6h, 077h, 002h, 0D4h, 056h, 037h

db 037h, 016h, 076h, 056h, 024h, 0F6h, 087h, 002h

db 026h, 057h, 047h, 002h, 0E6h, 0F6h, 002h, 096h

db 0D6h, 007h, 0F6h, 027h, 047h, 002h, 096h, 047h

db 012h, 000h

;db 'Show MessageBox but no import it!',0

.code

start:

invoke LoadLibrary,addr szUser32

invoke GetProcAddress,eax,offset szMessageBox

mov dwMessageBox,eax

invoke EnDeCryptString, addr szMessage

push MB_OK

lea eax,szTitle

push eax

lea eax,szMessage

push eax

push 0

call dword ptr [dwMessageBox]

invoke ExitProcess,NULL

EnDeCryptString proc pAddressString:DWORD

PUSH ESI

PUSH EDI

MOV EAX,pAddressString

MOV ESI,EAX

MOV EDI,EAX

DllCryptLoop:

LODSB

ROR AL,4

STOSB

CMP BYTE PTR [EDI],0

JNZ DllCryptLoop

POP EDI

POP ESI

RET

EnDeCryptString endp

end start

Sau khi biên dịch chương trình, chúng ta load vào olly thử xem nó search được badboy ko nhé.

3/-Anti Patching:

Thuở ban đầu khi tôi mới nghiên cứu reversing thì tôi đã đụng đến dạng anti patching này rồi. Kỹ thuật cũ kỹ này chính là dùng thuật tóan CRC để check các bytes tại 1 đọan code nào đó trong code section. Nếu CRC của đọan code đó bằng CRC chuẩn thì coi như đọan code đó ko bị patching. Nếu ko thì chương trình bị cracker patched code. Ta thử thí nghiệm như sau:

Ví dụ đầu tiên ta có một chương trình đơn giản sau:

.386

.model flat, stdcall

option casemap:none

include c:\masm32\include\windows.inc

include c:\masm32\include\kernel32.inc

includelib c:\masm32\lib\kernel32.lib

include c:\masm32\include\user32.inc

includelib c:\masm32\lib\user32.lib

.data

szTitle db 'No import func',0

szMessage db 'Show MessageBox but no import it!',0

.code

start:

push MB_OK

lea eax,szTitle

push eax

lea eax,szMessage

push eax

push 0

lea eax,MessageBox

call eax

invoke ExitProcess,NULL

end start

Nếu ta debugging nó trong Olly thì sẽ như nhận được như sau:

00401000 >/$ 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL

00401002 |. 8D05 00304000 LEA EAX,DWORD PTR DS:[403000] ; |

00401008 |. 50 PUSH EAX ; |Title = NULL

00401009 |. 8D05 0F304000 LEA EAX,DWORD PTR DS:[40300F] ; |

0040100F |. 50 PUSH EAX ; |Text = NULL

00401010 |. 6A 00 PUSH 0 ; |hOwner = NULL

00401012 |. 8D05 28104000 LEA EAX,DWORD PTR DS:[401028] ; |

00401018 |. FFD0 CALL EAX ; \MessageBoxA

0040101A |. 6A 00 PUSH 0 ; /ExitCode = 0

0040101C \. E8 01000000 CALL ; \ExitProcess

Từ addr 00401000 đến addr 0040101A là đọan code thể hiện gọi hàm MessageBoxA. Vậy chúng có chiều dài là 1Ah

Bây giờ ta thử viết một chương trình check xem CRC của đọan code này là bao nhiêu:

.386

.model flat, stdcall

option casemap:none

include \masm32\include\windows.inc

include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib

include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib

include \masm32\macros\macros.asm

.data

szTitle db 'No import func',0

szMessage db 'Show MessageBox but no import it!',0

dwCRC dd 0

strBenina db "CRC check",0

strFormat db "%x",0

.data?

strTmp db 20 dup(?)

.code

start:

code_check:

push MB_OK

lea eax,szTitle

push eax

lea eax,szMessage

push eax

push 0

lea eax,MessageBox

call eax

push offset code_check

push 1Ah

call CRC32

mov dwCRC,eax

invoke wsprintf,addr strTmp,addr strFormat,eax

invoke MessageBoxA,NULL,addr strTmp,addr strBenina,MB_OK

mov eax,dwCRC

.if eax==082492b0ah

invoke MessageBoxA,NULL,chr$("Program No Patching"),chr$("Normal"),MB_OK

.elseif

invoke MessageBoxA,NULL,chr$("Program Patched"),chr$("Very Bad"),MB_OK

.endif

invoke ExitProcess,0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CRC32 proc lData:DWORD, ptrData:DWORD

push esi

push ecx

push edx

mov esi, ptrData

xor edx, edx

or eax, -1

mov ecx, lData

CRC32_loop:

mov dl, byte ptr [esi]

xor dl, al

shr eax, 8

xor eax, dword ptr [crc32_table + 4*edx]

inc esi

dec ecx

jnz CRC32_loop

not eax

pop edx

pop ecx

pop esi

ret

crc32_table dd 000000000h, 077073096h, 0EE0E612Ch, 0990951BAh, 0076DC419h, 0706AF48Fh, 0E963A535h, 09E6495A3h, 00EDB8832h, 079DCB8A4h

dd 0E0D5E91Eh, 097D2D988h, 009B64C2Bh, 07EB17CBDh, 0E7B82D07h, 090BF1D91h, 01DB71064h, 06AB020F2h, 0F3B97148h, 084BE41DEh

dd 01ADAD47Dh, 06DDDE4EBh, 0F4D4B551h, 083D385C7h, 0136C9856h, 0646BA8C0h, 0FD62F97Ah, 08A65C9ECh, 014015C4Fh, 063066CD9h

dd 0FA0F3D63h, 08D080DF5h, 03B6E20C8h, 04C69105Eh, 0D56041E4h, 0A2677172h, 03C03E4D1h, 04B04D447h, 0D20D85FDh, 0A50AB56Bh

dd 035B5A8FAh, 042B2986Ch, 0DBBBC9D6h, 0ACBCF940h, 032D86CE3h, 045DF5C75h, 0DCD60DCFh, 0ABD13D59h, 026D930ACh, 051DE003Ah

dd 0C8D75180h, 0BFD06116h, 021B4F4B5h, 056B3C423h, 0CFBA9599h, 0B8BDA50Fh, 02802B89Eh, 05F058808h, 0C60CD9B2h, 0B10BE924h

dd 02F6F7C87h, 058684C11h, 0C1611DABh, 0B6662D3Dh, 076DC4190h, 001DB7106h, 098D220BCh, 0EFD5102Ah, 071B18589h, 006B6B51Fh

dd 09FBFE4A5h, 0E8B8D433h, 07807C9A2h, 00F00F934h, 09609A88Eh, 0E10E9818h, 07F6A0DBBh, 0086D3D2Dh, 091646C97h, 0E6635C01h

dd 06B6B51F4h, 01C6C6162h, 0856530D8h, 0F262004Eh, 06C0695EDh, 01B01A57Bh, 08208F4C1h, 0F50FC457h, 065B0D9C6h, 012B7E950h

dd 08BBEB8EAh, 0FCB9887Ch, 062DD1DDFh, 015DA2D49h, 08CD37CF3h, 0FBD44C65h, 04DB26158h, 03AB551CEh, 0A3BC0074h, 0D4BB30E2h

dd 04ADFA541h, 03DD895D7h, 0A4D1C46Dh, 0D3D6F4FBh, 04369E96Ah, 0346ED9FCh, 0AD678846h, 0DA60B8D0h, 044042D73h, 033031DE5h

dd 0AA0A4C5Fh, 0DD0D7CC9h, 05005713Ch, 0270241AAh, 0BE0B1010h, 0C90C2086h, 05768B525h, 0206F85B3h, 0B966D409h, 0CE61E49Fh

dd 05EDEF90Eh, 029D9C998h, 0B0D09822h, 0C7D7A8B4h, 059B33D17h, 02EB40D81h, 0B7BD5C3Bh, 0C0BA6CADh, 0EDB88320h, 09ABFB3B6h

dd 003B6E20Ch, 074B1D29Ah, 0EAD54739h, 09DD277AFh, 004DB2615h, 073DC1683h, 0E3630B12h, 094643B84h, 00D6D6A3Eh, 07A6A5AA8h

dd 0E40ECF0Bh, 09309FF9Dh, 00A00AE27h, 07D079EB1h, 0F00F9344h, 08708A3D2h, 01E01F268h, 06906C2FEh, 0F762575Dh, 0806567CBh

dd 0196C3671h, 06E6B06E7h, 0FED41B76h, 089D32BE0h, 010DA7A5Ah, 067DD4ACCh, 0F9B9DF6Fh, 08EBEEFF9h, 017B7BE43h, 060B08ED5h

dd 0D6D6A3E8h, 0A1D1937Eh, 038D8C2C4h, 04FDFF252h, 0D1BB67F1h, 0A6BC5767h, 03FB506DDh, 048B2364Bh, 0D80D2BDAh, 0AF0A1B4Ch

dd 036034AF6h, 041047A60h, 0DF60EFC3h, 0A867DF55h, 0316E8EEFh, 04669BE79h, 0CB61B38Ch, 0BC66831Ah, 0256FD2A0h, 05268E236h

dd 0CC0C7795h, 0BB0B4703h, 0220216B9h, 05505262Fh, 0C5BA3BBEh, 0B2BD0B28h, 02BB45A92h, 05CB36A04h, 0C2D7FFA7h, 0B5D0CF31h

dd 02CD99E8Bh, 05BDEAE1Dh, 09B64C2B0h, 0EC63F226h, 0756AA39Ch, 0026D930Ah, 09C0906A9h, 0EB0E363Fh, 072076785h, 005005713h

dd 095BF4A82h, 0E2B87A14h, 07BB12BAEh, 00CB61B38h, 092D28E9Bh, 0E5D5BE0Dh, 07CDCEFB7h, 00BDBDF21h, 086D3D2D4h, 0F1D4E242h

dd 068DDB3F8h, 01FDA836Eh, 081BE16CDh, 0F6B9265Bh, 06FB077E1h, 018B74777h, 088085AE6h, 0FF0F6A70h, 066063BCAh, 011010B5Ch

dd 08F659EFFh, 0F862AE69h, 0616BFFD3h, 0166CCF45h, 0A00AE278h, 0D70DD2EEh, 04E048354h, 03903B3C2h, 0A7672661h, 0D06016F7h

dd 04969474Dh, 03E6E77DBh, 0AED16A4Ah, 0D9D65ADCh, 040DF0B66h, 037D83BF0h, 0A9BCAE53h, 0DEBB9EC5h, 047B2CF7Fh, 030B5FFE9h

dd 0BDBDF21Ch, 0CABAC28Ah, 053B39330h, 024B4A3A6h, 0BAD03605h, 0CDD70693h, 054DE5729h, 023D967BFh, 0B3667A2Eh, 0C4614AB8h

dd 05D681B02h, 02A6F2B94h, 0B40BBE37h, 0C30C8EA1h, 05A05DF1Bh, 02D02EF8Dh

CRC32 endp

end start

Sau khi biên dịch, ta chạy thử chương trình. Đầu tiên nó chạy đọan code cần check CRC và hiện lên thông điệp:

Sau đó nó sẽ báo CRC của đọan code cần check là :

Vậy CRC chuẩn là 0x10fd82e6. Do lúc đầu ta chưa biết CRC là bao nhiêu nên ta giả sử nó là 082492b0ah :

.if eax==082492b0ah

Vì vậy chương trình mới hiện lên hộp thông điệp:

Bây giờ ta thay đổi chương trình trên tại đọan kiểm tra kết quả CRC, nếu CRC chuẩn tức là bằng 0x10fd82e6 thì báo chương trình ko bị patching, nếu ngược lại thì chương trình đã bị cracker can thiệp. Ta sửa đọan thành :

.if eax==010fd82e6h

Save lại và biên dịch lại. Sau khi biên dịch cho chạy chương trình chúng ta sẽ thấy chương trình thông báo như sau:

Bây giờ thử bật Olly lên và patch Nops dòng code “call eax” trong đọan code đó xem sao, chúng ta sẽ bị “tò tí te” liền.


Thôi hé. Phần này cũng khá dài rồi. Để dành tuts sau chúng ta nghiên cứu thêm . Phải nói là muôn vàng kỹ thuật. Viết hòai ko hết đâu. Đây chỉ là phần dạo đầu làm cho các bạn hứng khởi thôi. Các phần sau sẽ phức tạp hơn đôi chút. Chúc các bạn vui vẽ.

Benina