MASM的反反汇编技术
reference:http://www.aogosoft.com/downpage.asp?mode=viewtext&id=54
由于汇编语言是与机器语言机器码一一对应的,所以程序的代码非常简洁,编译、链接程序不会在其中加入任何其它代码,所以,用Win32DASM等把汇编工具反汇编汇编语言写的程序,其列出的汇编代码几乎与编写的顺序、过程、代码一模一样,这也是汇编语言简洁的证据。
但是这种过于简洁的代码却给了破解者提供了方便,破解者只需要有一定的Windows
SDK编程与汇编的经验,破解就非常简单,根本不需要用SoftICE这些动态工具就可以破解。于是,相应的防止跟踪的技术就出来了,比如花指令、不按规则调用API等等,今天就花指令和大家研究研究。
花指令,其实就是在程序中加入一些字节来干扰静态工具反汇编,毕竟汇编工具没有人的思维,所以这招非常好骗。
我在RadAsm中写入以下代码:
.386 .Model Flat, StdCall Option Casemap :None ;_____________________________________________________________ Include windows.inc Include user32.inc Include kernel32.inc IncludeLib user32.lib IncludeLib kernel32.lib ;_____________________________________________________________ .data Welcome db "欢迎来到汇编的世界",0 ;_____________________________________________________________ .CODE START: invoke MessageBox,0,offset Welcome,0,0 invoke ExitProcess,0 END START
对应的反汇编程序:
00401000 >/$ 6A 00 push 0 ; /(initial cpu selection) 00401002 |. 6A 00 push 0 ; |Title = NULL 00401004 |. 68 00304000 push 00403000 ; |欢迎来到汇编的世界 00401009 |. 6A 00 push 0 ; |hOwner = NULL 0040100B |. E8 08000000 call <jmp.&user32.MessageBoxA> ; \MessageBoxA 00401010 |. 6A 00 push 0 ; /ExitCode = 0 00401012 \. E8 07000000 call <jmp.&kernel32.ExitProcess> ; \ExitProcess 00401017 CC int3 00401018 $- FF25 08204000 jmp dword ptr [<&user32.MessageBoxA>>; user32.MessageBoxA 0040101E .- FF25 00204000 jmp dword ptr [<&kernel32.ExitProces>; kernel32.ExitProcess
修改code段代码为:
.CODE START: lea eax,Welcome invoke MessageBox,0,eax,0,0 invoke ExitProcess,0 END START
也就是说,我们并没有使用花指令,而是在使用字符串时先把字符串的地址传给eax,然后再把eax做为参数传给MessageBox,这样做,Win23DASM这些反汇编工具就无法识别了,好,用Win32DASM重新打开编译的文件,在[参考]菜单中,[字符串]这一项灰色显示,提示这个程序没有字符串,骗过它了!^_^
反汇编变成了这样:
00401000 >/$ 8D05 00304000 lea eax, dword ptr [403000] ; /(initial cpu selection) 00401006 |? 6A 00 push 0 00401008 |? 6A 00 push 0 0040100A |? 50 push eax 0040100B |. 6A 00 push 0 ; \MessageBoxA 0040100D |? E8 08000000 call <jmp.&user32.MessageBoxA> 00401012 \. 6A 00 push 0 ; \ExitProcess 00401014 ? E8 07000000 call <jmp.&kernel32.ExitProcess> 00401019 ? CC int3 0040101A ?- FF25 08204000 jmp dword ptr [<&user32.MessageBoxA>>; user32.MessageBoxA 00401020 ?- FF25 00204000 jmp dword ptr [<&kernel32.ExitProces>; kernel32.ExitProcess
还有就是使用花指令,花指令不但可以使反汇编工具无法识别出字符串,更会让它们把汇编出错误的代码,花指令一般都是使用一些无用的字节来进行干扰,但是干扰反汇编的字节仍是可以使用的,像这样子:
.data Welcome db "你是不是在搞笑哦!",0 ;_____________________________________________________________ .CODE START: jz @F jnz @F www db "欢迎来到汇编世界",0 @@: lea eax,www lea ebx,Welcome invoke MessageBox,0,eax,ebx,0 invoke ExitProcess,0 END START
反汇编后:
00401000 > $ /74 13 je short 00401015 00401002 . |75 11 jnz short 00401015 00401004 . |BB B6D3ADC0 mov ebx, C0ADD3B6 00401009 . |B4 B5 mov ah, 0B5 0040100B . |BD BBE3B1E0 mov ebp, E0B1E3BB 00401010 . |CA C0BD retf 0BDC0 00401013 . |E7 00 out 0, eax 00401015 > \8D05 04104000 lea eax, dword ptr [401004] 0040101B . 8D1D 00304000 lea ebx, dword ptr [403000] 00401021 . 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL 00401023 . 53 push ebx ; |Title => "你是",B2,"",BB,"是在",B8,"阈",A6,"?,B6,"?,A1,"" 00401024 . 50 push eax ; |Text => ""BB,"",B6,"?,AD,"?,B4,"?,BD,"",BB,"惚嗍?,BD,"? 00401025 . 6A 00 push 0 ; |hOwner = NULL 00401027 . E8 08000000 call <jmp.&user32.MessageBoxA> ; \MessageBoxA 0040102C . 6A 00 push 0 ; /ExitCode = 0 0040102E . E8 07000000 call <jmp.&kernel32.ExitProcess> ; \ExitProcess 00401033 CC int3 00401034 $- FF25 08204000 jmp dword ptr [<&user32.MessageBoxA>>; user32.MessageBoxA 0040103A .- FF25 00204000 jmp dword ptr [<&kernel32.ExitProces>; kernel32.ExitProcess
感觉还是有些明显,我们手动调用API来试试。
.data Welcome db "你是不是在搞笑哦!",0 ;_____________________________________________________________ .CODE START: lea eax,Welcome push 0 push 0 push eax push 0 jz @F jnz @F www db "欢迎来到汇编世界",0 @@: call [MessageBox] invoke ExitProcess,0 END START
反汇编后:
00401000 > $ 8D05 00304000 lea eax, dword ptr [403000] ; (initial cpu selection) 00401006 ? 6A 00 push 0 00401008 ? 6A 00 push 0 0040100A ? 50 push eax 0040100B . 6A 00 push 0 0040100D ? 74 13 je short 00401022 0040100F ? 75 11 jnz short 00401022 00401011 ? BB B6D3ADC0 mov ebx, C0ADD3B6 00401016 ? B4 B5 mov ah, 0B5 00401018 ? BD BBE3B1E0 mov ebp, E0B1E3BB 0040101D ? CA C0BD retf 0BDC0 00401020 ? E7 00 out 0, eax 00401022 ? E8 07000000 call <jmp.&user32.MessageBoxA> 00401027 . 6A 00 push 0 ; \MessageBoxA 00401029 ? E8 06000000 call <jmp.&kernel32.ExitProcess> 0040102E .- FF25 08204000 jmp dword ptr [<&user32.MessageBoxA>>; \ExitProcess 00401034 $- FF25 00204000 jmp dword ptr [<&kernel32.ExitProces>; kernel32.ExitProcess
用OD调试的时候感觉到有不习惯的了。
下面是一个完整的示例:
;================= ;完整API花指令示例: ;================= .386 .Model Flat, StdCall Option Casemap :None ; 不区分大小写(对API与API常数无效) ;_____________________________________________________________ Include windows.inc Include user32.inc Include kernel32.inc IncludeLib user32.lib IncludeLib kernel32.lib .CODE START: push 0 push 0 push offset Welcome push 0 jz @F jnz @F Welcome db "Welcome",0 @@: mov eax,[MessageBox+4] sub eax,4 jnz @F Welcome1 db "Welcome",0 @@: call eax invoke ExitProcess,0 END START
反汇编代码:
00401000 > $ 6A 00 push 0 00401002 . 6A 00 push 0 00401004 . 68 0F104000 push 0040100F 00401009 . 6A 00 push 0 0040100B . 74 0A je short 00401017 0040100D . 75 08 jnz short 00401017 0040100F . 57 push edi 00401010 . 65:6C ins byte ptr es:[edi], dx 00401012 . 636F 6D arpl word ptr [edi+6D], bp 00401015 65 db 65 ; CHAR 'e' 00401016 00 db 00 00401017 . B8 36104000 mov eax, 00401036 0040101C . 83E8 04 sub eax, 4 0040101F . 75 08 jnz short 00401029 00401021 . 57 push edi 00401022 . 65:6C ins byte ptr es:[edi], dx 00401024 . 636F 6D arpl word ptr [edi+6D], bp 00401027 65 db 65 ; CHAR 'e' 00401028 00 db 00 00401029 . FFD0 call eax 0040102B . 6A 00 push 0 ; /ExitCode = 0 0040102D . E8 06000000 call <jmp.&kernel32.ExitProcess> ; \ExitProcess 00401032 .- FF25 08204000 jmp dword ptr [<&user32.MessageBoxA>>; user32.MessageBoxA 00401038 .- FF25 00204000 jmp dword ptr [<&kernel32.ExitProces>; kernel32.ExitProcess
惨不忍睹,删除模块分析后
00401000 > 6A 00 push 0 00401002 6A 00 push 0 00401004 68 0F104000 push 0040100F ; ASCII "Welcome" 00401009 6A 00 push 0 0040100B 74 0A je short 00401017 0040100D 75 08 jnz short 00401017 0040100F 57 push edi 00401010 65:6C ins byte ptr es:[edi], dx 00401012 636F 6D arpl word ptr [edi+6D], bp 00401015 65:00B8 3610400>add byte ptr gs:[eax+401036], bh 0040101C 83E8 04 sub eax, 4 0040101F 75 08 jnz short 00401029 00401021 57 push edi 00401022 65:6C ins byte ptr es:[edi], dx 00401024 636F 6D arpl word ptr [edi+6D], bp 00401027 65:00FF add bh, bh 0040102A D06A 00 shr byte ptr [edx], 1 0040102D E8 06000000 call <jmp.&kernel32.ExitProcess> 00401032 - FF25 08204000 jmp dword ptr [<&user32.MessageBoxA>>; user32.MessageBoxA 00401038 - FF25 00204000 jmp dword ptr [<&kernel32.ExitProces>; kernel32.ExitProcess
感觉没多大变化,看来,花指令会让人发晕的。