矛与盾的较量(1)——花指令

    技术2022-05-11  101

    有矛就有盾。 所以我们要讨论加密技术。 我们知道,所有的编译型语言,例如VC、BCB、Delphi和Win32ASM……最终都会把源代码编译成机器能识别的0和1——因此也能够反过来把这些0和1反编译成汇编代码。反编译有什么用呢?试想想,你辛辛苦苦写了一个perfect的软件出来,正准备把它卖上100万份,忽然!在市面上出现了很多仿制你的东西……hoho,不知道你会怎么想呢?反正我是会欲哭无泪的。还有另外一种情况,你的软件是用注册码的形式来授权的,每份license要卖30个美刀。呵呵,正当你在考虑着一年后是去加利福尼亚还是夏威夷度假的时候,你的软件被Crack了——也就是说,你一分钱都不会得到……(啊!我想跳楼啦!!) 所以我们要讨论如何给自己的程序加密。这次就先说说最简单的花指令。 在解释这个“花指令”之前,不妨先做几个小小的实验。 我们先来写一个程序,命名为hua.asm,内容如下:
    ;***************************************************************;花指令实验1;作者:罗聪;日期:2002-8-21;***************************************************************.386.model flat, stdcalloption casemap:noneinclude /masm32/include/windows.incinclude /masm32/include/kernel32.incinclude /masm32/include/user32.incincludelib /masm32/lib/kernel32.libincludelib /masm32/lib/user32.lib.dataszText        db    "嘿嘿,这是一个花指令程序……", 0szCaption    db    "花指令演示 by LC 2002-8-21", 0.codemain:    jmp Do_ItDo_It:    invoke MessageBox, NULL, addr szText, addr szCaption, MB_OK    invoke ExitProcess, 0end main
    然后用W32Dasm v10来反编译它,得到的结果如下:(由于篇幅所限,这里只列出关键部分)
    +++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++//********************** Start of Code in Object .text **************Program Entry Point = 00401000 (hua.exe File Offset:00001600)//******************** Program Entry Point ********:00401000 EB00                    jmp 00401002* Referenced by a (U)nconditional or ?onditional Jump at Address:|:00401000(U)|:00401002 6A00                    push 00000000* Possible StringData Ref from Data Obj ->"花指令演示 by LC 2002-8-21"                                  |:00401004 681F304000              push 0040301F* Possible StringData Ref from Data Obj ->"嘿嘿,这是一个花指令程序……"                                  |:00401009 6800304000              push 00403000:0040100E 6A00                    push 00000000* Reference To: USER32.MessageBoxA, Ord:01BBh                                  |:00401010 E80D000000              Call 00401022:00401015 6A00                    push 00000000* Reference To: KERNEL32.ExitProcess, Ord:0075h                                  |:00401017 E800000000              Call 0040101C
    哇,好夸张啊!你可能会说。反编译出来的代码几乎是跟源代码一一对应的,这样一来?我们的程序还有什么秘密可言呢?完全可以从反编译的结果中理解程序的功能。 而且我们还可以在W32Dasm的“String Data References”中得到:
    "嘿嘿,这个是一个花指令程序……""花指令演示 by LC 2002-8-21"
    把刚才的源程序稍做修改,来做第二个实验:
    ;***************************************************************;花指令实验2;作者:罗聪;日期:2002-8-21;***************************************************************.386.model flat, stdcalloption casemap:noneinclude /masm32/include/windows.incinclude /masm32/include/kernel32.incinclude /masm32/include/user32.incincludelib /masm32/lib/kernel32.libincludelib /masm32/lib/user32.lib.dataszText        db    "嘿嘿,这是一个花指令程序……", 0szCaption    db    "花指令演示 by LC 2002-8-21", 0.codemain:    jz Do_It    ;注意这里和第一个实验中的源程序的区别    jnz Do_It    ;注意这里和第一个实验中的源程序的区别Do_It:    invoke MessageBox, NULL, addr szText, addr szCaption, MB_OKend main
    用W32Dasm反编译一下:
    +++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++//********************** Start of Code in Object .text **************Program Entry Point = 00401000 (hua.exe File Offset:00001600)//******************** Program Entry Point ********:00401000 7402                    je 00401004:00401002 7500                    jne 00401004* Referenced by a (U)nconditional or ?onditional Jump at Addresses:|:00401000?, :00401002?|:00401004 6A00                    push 00000000* Possible StringData Ref from Data Obj ->"花指令演示 by LC 2002-8-21"                                  |:00401006 681F304000              push 0040301F* Possible StringData Ref from Data Obj ->"嘿嘿,这是一个花指令程序……"                                  |:0040100B 6800304000              push 00403000:00401010 6A00                    push 00000000* Reference To: USER32.MessageBoxA, Ord:01BBh                                  |:00401012 E801000000              Call 00401018
    可以看出,这时的W32Dasm反编译出来的汇编指令还是正确的。但是W32Dasm其实已经逐渐落入我们设下的“陷阱”了。 下面我们来做第三个实验,把源程序改成:
    ;***************************************************************;花指令实验3;作者:罗聪;日期:2002-8-21;***************************************************************.386.model flat, stdcalloption casemap:noneinclude /masm32/include/windows.incinclude /masm32/include/kernel32.incinclude /masm32/include/user32.incincludelib /masm32/lib/kernel32.libincludelib /masm32/lib/user32.lib.dataszText        db    "嘿嘿,这是一个花指令程序……", 0szCaption    db    "花指令演示 by LC 2002-8-21", 0.codemain:    jz Do_It    ;注意这里和第一个实验中的源程序的区别    jnz Do_It    ;注意这里和第一个实验中的源程序的区别    db 0E8h        ;注意这里和第二个实验中的源程序的区别Do_It:    invoke MessageBox, NULL, addr szText, addr szCaption, MB_OK    invoke ExitProcess, 0end main
    我们来看看W32Dasm中反编译出来的东西:
    +++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++//********************** Start of Code in Object .text **************Program Entry Point = 00401000 (hua.exe File Offset:00001600)//******************** Program Entry Point ********:00401000 7403                    je 00401005:00401002 7501                    jne 00401005:00401004 E86A00681D              call 1DA81073:00401009 304000                  xor byte ptr [eax+00], al* Possible StringData Ref from Data Obj ->"嘿嘿,这是一个花指令程序……"                                  |:0040100C 6800304000              push 00403000:00401011 6A00                    push 00000000* Reference To: USER32.MessageBoxA, Ord:01BBh                                  |:00401013 E80E000000              Call 00401026:00401018 6A00                    push 00000000* Reference To: KERNEL32.ExitProcess, Ord:0075h                                  |:0040101A E801000000              Call 00401020
    呵呵,很明显了,这时的 00401004 到 00401009 行出错了,而且这时查看“String Data References”,也只剩下了:
    "嘿嘿,这是一个花指令程序……"
    让我们进一步隐藏信息,做第四个实验:
    ;***************************************************************;花指令实验4;作者:罗聪;日期:2002-8-21;***************************************************************.386.model flat, stdcalloption casemap:noneinclude /masm32/include/windows.incinclude /masm32/include/kernel32.incinclude /masm32/include/user32.incincludelib /masm32/lib/kernel32.libincludelib /masm32/lib/user32.lib.dataszText        db    "嘿嘿,这是一个花指令程序……", 0szCaption    db    "花指令演示 by LC 2002-8-21", 0.codemain:    jz Do_It    ;注意这里和第一个实验中的源程序的区别    jnz Do_It    ;注意这里和第一个实验中的源程序的区别    db 0E8h        ;注意这里和第二个实验中的源程序的区别Do_It:    lea eax, szText        ;注意这里和第三个实验中的源程序的区别    lea ebx, szCaption    ;注意这里和第三个实验中的源程序的区别    invoke MessageBox, NULL, eax, ebx, MB_OK    ;注意这里和第三个实验中的源程序的区别    invoke ExitProcess, 0end main
    编译,再用W32Dasm反编译,得到的是:
    +++++++++++++++++++ ASSEMBLY CODE LISTING ++++++++++++++++++//********************** Start of Code in Object .text **************Program Entry Point = 00401000 (hua.exe File Offset:00001600)//******************** Program Entry Point ********:00401000 7403                    je 00401005:00401002 7501                    jne 00401005:00401004 E88D050030              call 30401596:00401009 40                      inc eax:0040100A 008D1D1D3040            add byte ptr [ebp+40301D1D], cl:00401010 006A00                  add byte ptr [edx+00], ch:00401013 53                      push ebx:00401014 50                      push eax:00401015 6A00                    push 00000000* Reference To: USER32.MessageBoxA, Ord:01BBh                                  |:00401017 E80E000000              Call 0040102A:0040101C 6A00                    push 00000000* Reference To: KERNEL32.ExitProcess, Ord:0075h                                  |:0040101E E801000000              Call 00401024

    呵呵,这次不但面目全非了,而且“String Data References”按钮已经变成了灰色。什么蛛丝马迹都没有了。各位看官看到这里明白了吗?其实花指令就是人为地构造一些“陷阱”和一些无用的字节。例如第二个实验中的:jz Do_Itjnz Do_It其实这个跟 jmp Do_It 还不是一样吗?(呵呵,如果在大学的期末考试里这样写,一定会被判不及格……)是的,其实程序原有的功能和逻辑还是一样的,我们只不过是换了一种表现形式而已。然而,反编译工具是没有人脑那么智能的,它们往往就会把这些指令理解错,从而错误地确定了指令的起始位置。要实现这种绝对跳转的功能,还可以用很多的方法,例如:Push Do_Itret花指令是很容易理解的,不过大家要注意适时而用,不要滥用啊,能起到迷惑破解者和隐藏信息的作用就行了,不然将来要维护代码时,我怕被迷惑的反而是你自己哦,呵呵……

     

    (文章来源 & 更多我的原创文章:http://laoluoc.yeah.net)


    最新回复(0)