`
datoplay
  • 浏览: 1615468 次
文章分类
社区版块
存档分类
最新评论

软件保护机制小窥

 
阅读更多
保护机制小窥

【声明】
我写文章以交流为主,希望大家在转载时能保持文章的完整性。

【前言】
这次以介绍保护机制为主,就不写什么脱壳方法了,其实以前我也误导了不少善良的观众。了解一个加壳软件最主要的应该是了解其保护机制,这也是我后来才领悟的一点。以下介绍的一点保护机制的知识。这里只为了让大家和我一起来共同学习和了解保护机制的知识。

水货作者:ljttt
出厂日期:2001-01-01(水货的东东一般都这样写出厂日期的)

①、首先,我们来看个比较简单的自身保护方法。这段代码如下:

0040CC54:03F3addesi,ebx<--esi指向某段代码,ecx为代码的长度(DWORD)
0040CC56:8B06moveax,dwordptr[esi]<--取出代码中的4个字节
0040CC58:33D0xoredx,eax<--XOR异或
0040CC5A:F7D2notedx<--取反
0040CC5C:33D1xoredx,ecx<--与ecx(代码长度)异或
0040CC5E:03D0addedx,eax<--与代码中的4个字节相加
0040CC60:83C604addesi,00000004<--定位到代码中的下4个字节
0040CC63:49dececx<--代码长度减一
0040CC64:75F0jnz0040CC56<--循环

先来描述一下这段代码的功能:可以看到这段代码用ESI作为指针,用ECX保存长度。把ESI指向的数据进行异或取反,最后在EDX中得到一个“值”。

那么它和自身保护有什么联系呢?我来简单说一下,如果ESI=0040CC54,ECX=0040CC64-0040CC54。那么这段代码是不是就是把自身的代码进行运算(异或取反)呢?OK!

那么如果你这段代码中间设下一个断点,会有什么变化呢?运算得到的“值”会和原来未设断时的相同吗?

我们以SoftICE来简单介绍一下吧。当你在SoftICE的调试环境下,设下一个断点时,那么这个断点所在的代码的第一个字节就会变成0xCC。
这样由于设下断点,代码就被改变了,那么运算的“值”就和未设断时不一样了。你可能想到有了这个值,就可以用比较的方法来判断是否自身是否被设下断点了。不错,这是一种方法,但是这很容易被......在加壳软件中,一般会把这个“值”作为还原密匙,来还原下一段代码。
也就是所谓的SMC技巧来还原代码。

(但是如果你在SoftICE中用D指令来显示这行代码,却没有发现变化。呵呵,但是,如果你再启动另一个调试器TRW2000,来显示这行代码,再看看?呵呵,明白了吗?)

②、SMC技巧来还原代码。
在加壳软件中,分段还原代码是一种很普遍的方法了。也许你有过这样的经历。(怎么,弄得象散文了?!)你跟踪过某个软件,发现了某段代码,比如CPUID(相应的十六进制代码为0x0F0xA2)。却发现当你用十六进制编辑软件来查找0x0F0xA2时,却怎么也找不到,Why?

其实道理很简单,就是在程序的可执行文件中保存的是加密了的数据,只有程序在运行时才会由程序在某处由一段还原代码来解密这段加密数据,(还原后的数据就是你在调试器中可以“看”到的真实的代码)。然后,程序才执行这段还原后的代码。现在你清楚了吧!比如象①中介绍的那段代码是用来形成还原密匙的,只有密匙正确时,也就是说它先四下“打量”一下,当“发现”自身没有被修改(或者被设下断点)时,才“悄悄地”还原出另一段被加密了的代码。然后继续!
有点意思吧!在加壳软件中,如果它“想”保护某段代码,就会加密它,然后在程序运行时用另一段代码形成密匙来还原它!这样就防止你静态分析它,当然为了防止你用动态跟踪的方法,所以它还结合了①中介绍的自身保护方法。这样,如果你误入陷阱(在其自身保护的某处设下了一个断点),那么还原出的代码就是一堆垃圾代码。如果这样,你可不要写信给作者,说他程序编得有问题哦?!

(当然SMC技巧可以被用作多种用途。不要大家有先入为主的概念,SMC的技巧既可以被加壳软件用作自身保护的一种方法,也可以被Cracker作为一种破解的方法,所以......怎么用,还在于你!......你想用来编“病毒”.....老天,为什么天才总有点反叛因子!)

前面介绍了简单的自身保护技巧,也许你早就想好了对付它的方法,比如:
不设任何断点,用单步跟踪的方法
或者先跟踪一次记下正确的密匙,下次跟踪时任意设断,只在它取密匙时“给”个正确的给它。
或者用BPM断点只跟踪数据、不跟踪代码的方法进行动态跟踪。
你还可以想得更多。。。。

当然,为了更好地保护自身,所以在加壳软件中也不会只是这么简单地保护自己,你猜加壳软件中又会用到什么保护方法可以防止以上方法呢?

③、一种反跟踪方法:API调用的变形。
你也许喜欢首先在某个关键的API函数处设断,然后才进入程序代码中进行跟踪。但是在加壳软件中这种方法可就要小心了。
我们来看看这段代码:

015F:00411B6A33C0XOREAX,EAX<--ESI指向API函数地址的入口,如CreateFileA()
015F:00411B6CACLODSB<--获取一个字节
015F:00411B6D3C50CMPAL,50<--判断是否为50
015F:00411B6F720FJB00411B80<--小于50,则跳转到00411B80
015F:00411B713C57CMPAL,57<--判断是否为57
015F:00411B73770BJA00411B80<--大于57,则跳转到00411B80
......
015F:00411BD3897A01MOV[EDX+01],EDI
015F:00411BD68B831F7B0000MOVEAX,[EBX+00007B1F]
015F:00411BDC8B8B237B0000MOVECX,[EBX+00007B23]
015F:00411BE28B93277B0000MOVEDX,[EBX+00007B27]
015F:00411BE88BBB3B7B0000MOVEDI,[EBX+00007B3B]
015F:00411BEE8BB3377B0000MOVESI,[EBX+00007B37]
015F:00411BF48BAB337B0000MOVEBP,[EBX+00007B33]
015F:00411BFA8B9B2B7B0000MOVEBX,[EBX+00007B2B]
015F:00411C00E900000000JMP00411C05<--此处的跳转将被修改为API函数地址内的一条指令处

(说明:进入这段代码时,ESI指向了某个API函数的入口地址,ESP指向的堆栈中压入了该API函数需要的各个参数。由于代码较长,没有完整列出)

以上这段代码的作用,就是通过分析(或者说反汇编)API函数开始的部分代码,然后把这部分代码“复制”到自己的进程空间中执行后,再进入该API函数的内部某处代码继续执行API函数。

这样,当你在此API函数入口处(比如:bpxCreateFileA)设断时,就会“拦”不到它,为什么?因为,它不从API函数入口处执行。而是绕了个弯从“侧门”进入的。瞧,加壳软件多有意思!也许,这时你会想,那么就在API函数的内部某处代码设断不就行了吗?你要小心,加壳软件有善良的,也有喜欢“恶作剧”的,它通过分析API函数开始部分的代码,一方面进行“反汇编”,另一方面,如果你在它分析的代码中设下了断点时,也可能他会痛下杀手,因为断点的代码为0xCC,它可不喜欢在API函数中出现这种指令。如果你由此当机了..........


④、态跟踪的方法。
当然,加壳软件也可能不只是把眼光放在防范你设断点,也可能直接就把“眼光”放在防范调试状态上了。比如最直接的就是检测你的当前环境中是否加载了调试器或者是某些工具软件。比如:

Thismethodismostknownas'MeltICE'becauseithasbeenfreelydistributed
viawww.winfiles.com.HoweveritwasfirstusedbyNuMegapeopletoallowSymbol
LoadertocheckifSoftICEwasactiveornot(thecodeislocatedinsidenmtrans.dll).

Thewayitworksisverysimple:
IttriestoopenSoftICEdrivershandles(SICE,SIWVIDforWin9x,NTICEforWinNT)
withtheCreateFileAAPI.

Hereisasample(checkingfor'SICE'):

BOOLIsSoftIce95Loaded()
{
HANDLEhFile;
hFile=CreateFile("////.//SICE",GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile!=INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
returnTRUE;
}
returnFALSE;
}

以上是摘自FrogsICE的文档。利用CreateFile()打开一些特殊的“文件”,如果返回值不是-1,它就可以“发现”加载了SoftICE。当然这种方法由于可以在WIN98/NT下通用,所以很常见。
类似的,如果你把检测的字符串//./SICE改成
//./NTICE检测NT下的SoftICE
//./FILEMON检测FileMon
//./REGMON检测RegMon
//./TRW检测Trw
//./TRWDEBUG检测Trw
//./ICEDUMP检测IceDump
就可以“发现”其他的跟踪了。

另一种常见的检测SoftICE的方法如下,同样摘自FrogsICE的文档。

**SOFTICESHOULDNOTBELOADEDSOTHATFROGSICECANDETECTTHISMETHOD**

ThismethodofdetectionofSoftICE(aswellasthefollowingone)is
usedbythemajorityofpackers/encryptorsfoundonInternet.
ItseeksthesignatureofBoundsCheckerinSoftICE

movebp,04243484Bh;'BCHK'
movax,04h
int3
cmpal,4
jnzSoftICE_Detected

其实检测SoftICE方法有很多,在FrogsICE的文档中介绍了一些,这里的介绍只是窥其一斑而已。如果你有最“新”的反跟踪方法,可一定要通知我哦。^_^


⑤、自身保护和态跟踪相结合:
最后我们来看看这段代码:

015F:0040DDD801FFADDEDI,EDI
015F:0040DDDAC783CB18000090010000MOVDWORDPTR[EBX+000018CB],00000190
015F:0040DDE48BEBMOVEBP,EBX
015F:0040DDE6BA561E0000MOVEDX,00001E56
015F:0040DDEB03D3ADDEDX,EBX
015F:0040DDED52PUSHEDX
015F:0040DDEE6467FF360000PUSHDWORDPTRFS:[0000]<--SEH
015F:0040DDF4646789260000MOVFS:[0000],ESP<--SEH
015F:0040DDFA89A3A3760000MOV[EBX+000076A3],ESP
015F:0040DE00BECD1E0000MOVESI,00001ECD
015F:0040DE0503F3ADDESI,EBX
015F:0040DE078BFEMOVEDI,ESI<--EDI=40DECD
015F:0040DE09B90F0A0000MOVECX,00000A0F<--ECX=0xA0F,ECX保存的是循环次数
015F:0040DE0E8B93FC760000MOVEDX,[EBX+000076FC]

;--------------------------------------------------------------------------------------------------
;以下这一段代码同1中介绍的代码类似。
;也就是把代码段(015F:40D8E6-015F:40DECA)之间的代码和EDX的初始值进行运算来形成一个“密匙”
;结果仍然保存在EDX中。
;--------------------------------------------------------------------------------------------------
015F:0040DE1456PUSHESI<--循环开始处
015F:0040DE1551PUSHECX<--入栈保存,ECX保存的是循环的次数=A0F。
015F:0040DE16B979010000MOVECX,00000179
015F:0040DE1BBEE6180000MOVESI,000018E6
015F:0040DE2003F3ADDESI,EBX<--ESI=40C000+18E6=40D8E6。(40C000是程序入口)
015F:0040DE228B06MOVEAX,[ESI]<--取代码中的4个字节
015F:0040DE2433D0XOREDX,EAX
015F:0040DE2633D1XOREDX,ECX
015F:0040DE2883C604ADDESI,04
015F:0040DE2B49DECECX<--循环次数减一,ECX初始值为179
015F:0040DE2C75F4JNZ0040DE22<--这一段是和前面介绍的相同的方法进行自身保护
015F:0040DE2E59POPECX<--出栈
015F:0040DE2F5EPOPESI<--出栈
;--------------------------------------------------------------------------------------------------
;这段代码用EDX中的“密匙”来还原EDI指向中的被加密了的代码,EDI初始值为40DECD
;--------------------------------------------------------------------------------------------------
015F:0040DE30ADLODSD
015F:0040DE3133C2XOREAX,EDX
015F:0040DE33ABSTOSD
;--------------------------------------------------------------------------------------------------
;这段代码用来进行反跟踪
;--------------------------------------------------------------------------------------------------
015F:0040DE340F018BA57A0000SIDTFWORDPTR[EBX+00007AA5]<--取IDTR的内容
015F:0040DE3B8BB3A77A0000MOVESI,[EBX+00007AA7]<--取IDT表基地址
015F:0040DE41894E08MOV[ESI+08],ECX<--修改int1的处理程序地址为ECX,让你死翘翘。
;--------------------------------------------------------------------------------------------------
;把“密匙”进行变换。
;--------------------------------------------------------------------------------------------------
015F:0040DE443393521E0000XOREDX,[EBX+00001E52]
015F:0040DE4A8BF7MOVESI,EDI
015F:0040DE4CEB70JMP0040DEBE
......(省略)
015F:0040DEBEFF834E1E0000INCDWORDPTR[EBX+00001E4E]
015F:0040DEC433D1XOREDX,ECX
;--------------------------------------------------------------------------------------------------
;判断循环是否结束,即此时后面的所有被加密的代码都已经被还原
;--------------------------------------------------------------------------------------------------
015F:0040DEC649DECECX<--循环次数减一,ECX初始值为A0F
015F:0040DEC70F8547FFFFFFJNZ0040DE14<--循环结束处
015F:0040DECD5FPOPEDI<--被加密了的代码
015F:0040DECE44INCESP<--未还原的代码

这段代码比较长,所以要看懂它得花点时间。这是一种把“态跟踪”和“自身保护”结合的一种方法。
可以看到015F:0040DECD之后的代码已经被加密了,这段代码就是用来还原被加密了的代码的。当这段代码循环结束后,后面的被加密了的代码就已经还原出来了,这就是SMC技巧的应用。在这段代码中“密匙”是由前面所有的代码来运算得到的。并且每循环一次就变换一次。这就是1中介绍的自身保护。防止你修改它的代码或者设下断点跟踪。
另外,程序中还加入了一种“态跟踪”的方法,就是修改了单步中断的中断处理程序的地址。这样,你的跟踪环境就被破坏了。

015F:0040DE340F018BA57A0000SIDTFWORDPTR[EBX+00007AA5]<--取IDTR的内容
015F:0040DE3B8BB3A77A0000MOVESI,[EBX+00007AA7]<--取IDT表基地址
015F:0040DE41894E08MOV[ESI+08],ECX<--修改int1的处理程序地址为ECX,让你死翘翘。


这就是加壳软件的特点,攻防结合。所以一不小心,你就可能落入了它设下的陷阱,见到了“如来佛”。所以为了防止被它送到西天。你就得下点功夫,了解自身保护、反跟踪的特点和技巧。加壳软件一般就是这样一个陷阱重重的地方。当然加壳软件的保护机制也有它的弱点,只要你的程序指令机器“读”得懂,那么动态跟踪不行,就有静态分析,或者动静结合。所以才会各种相应的脱壳机的出现。当然这是一个“矛”和“盾”的关系,孰强孰弱,我想关键在于运用得当和推陈出新。比如,我常会结合MD5/RSA/BLOWFISH等加密算法进行注册码计算,怎么样?!哈哈,然后用IF指令进行注册判断!?...................

【后记】
由于这些保护机制的方法出现的频率比较多,所以介绍一下也无妨。其实,这些东西很早就有了。但是对于生产水货的我,常常喜欢来点新瓶装旧酒。另外,我对ANTI-DEBUG了解得还不全面,也希望能够抛砖引玉,能引出更多的高手,让大家来进行打假。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics