本帖最后由 manbug 于 2010-10-14 08:22 编辑
看了 CjwNull 大的文章 和 Hmily 大的文章,深受启发,因为对皮肤很感兴趣,所以自己也试着破了一下,并试着做成内存加载DLL(免费版不支持静态编译),顺便也可以复习一下PE结构;
参考文章:
[LCG原创] 也谈SkinSharp的破解
SkinSharp CracKed By LCG
按照CjwNull 大的方法直接找到关键地点:10021570 A1 98CA0210 mov eax, dword ptr [1002CA98] ; 大小
10021575 8B0D 94CA0210 mov ecx, dword ptr [1002CA94] ; 大小
1002157B 8B15 8CCA0210 mov edx, dword ptr [1002CA8C]
10021581 57 push edi
10021582 68 FF00FF00 push 0FF00FF
10021587 50 push eax
10021588 51 push ecx
10021589 6A 00 push 0
1002158B 6A 00 push 0
1002158D 52 push edx
1002158E 8B96 B0010000 mov edx, dword ptr [esi+1B0]
10021594 50 push eax
10021595 8B86 B8010000 mov eax, dword ptr [esi+1B8]
1002159B 51 push ecx
1002159C 8D4410 F0 lea eax, dword ptr [eax+edx-10]
100215A0 99 cdq
100215A1 2BC2 sub eax, edx
100215A3 D1F8 sar eax, 1
100215A5 50 push eax
100215A6 8B86 B4010000 mov eax, dword ptr [esi+1B4]
100215AC 2BC1 sub eax, ecx
100215AE 83E8 0C sub eax, 0C
100215B1 50 push eax
100215B2 55 push ebp
100215B3 E8 8898FEFF call 1000AE40 ;这个call其实是关键了
CjwNull 大说只要将 100215B2 这处改成push eax或其它的就行了,我试了,的确可行(废话),但是CjwNull 大并未说为什么要改这处,于是自己调试了,载入作者提供的演示版程序在100215B3处下断,断下来后单步步入call,会看到:1000AE40 8B4424 30 mov eax, dword ptr [esp+30]
1000AE44 85C0 test eax, eax
1000AE46 74 06 je short 1000AE4E
1000AE48 C700 00000000 mov dword ptr [eax], 0
1000AE4E 53 push ebx
1000AE4F 8B5C24 14 mov ebx, dword ptr [esp+14]
1000AE53 56 push esi
1000AE54 57 push edi
1000AE55 85DB test ebx, ebx
1000AE57 0F8E FF000000 jle 1000AF5C
1000AE5D 8B5424 30 mov edx, dword ptr [esp+30]
1000AE61 85D2 test edx, edx
1000AE63 0F8E F3000000 jle 1000AF5C
1000AE69 8B7C24 20 mov edi, dword ptr [esp+20]
1000AE6D 85FF test edi, edi
1000AE6F 0F8E E7000000 jle 1000AF5C
1000AE75 8B4424 34 mov eax, dword ptr [esp+34]
1000AE79 85C0 test eax, eax
1000AE7B 0F8E DB000000 jle 1000AF5C
1000AE81 8B4C24 24 mov ecx, dword ptr [esp+24]
1000AE85 85C9 test ecx, ecx
1000AE87 0F84 CF000000 je 1000AF5C
1000AE8D 3BDA cmp ebx, edx
1000AE8F 75 31 jnz short 1000AEC2
1000AE91 3BF8 cmp edi, eax
1000AE93 75 2D jnz short 1000AEC2
1000AE95 8B7424 38 mov esi, dword ptr [esp+38] ;上面有很多跳转
1000AE99 56 push esi
1000AE9A 50 push eax
1000AE9B 8B4424 34 mov eax, dword ptr [esp+34]
1000AE9F 52 push edx
1000AEA0 8B5424 34 mov edx, dword ptr [esp+34]
1000AEA4 50 push eax
1000AEA5 8B4424 28 mov eax, dword ptr [esp+28]
1000AEA9 52 push edx
1000AEAA 8B5424 24 mov edx, dword ptr [esp+24] ;我们改的参数给了edx
1000AEAE 51 push ecx
1000AEAF 8B4C24 2C mov ecx, dword ptr [esp+2C]
1000AEB3 57 push edi
1000AEB4 53 push ebx
1000AEB5 50 push eax
1000AEB6 51 push ecx
1000AEB7 52 push edx
1000AEB8 FF15 34610210 call near dword ptr [10026134] ; MSIMG32.TransparentBlt
一直单步到1000AEB8此处,我们会发现原来CjwNull 大让我们改的实际上是给TransparentBlt这个函数的第一个参数,我们看看这个函数的原型:BOOL TransparentBlt(
HDC hdcDest, // handle to destination DC
int nXOriginDest, // x-coord of destination upper-left corner
int nYOriginDest, // y-coord of destination upper-left corner
int nWidthDest, // width of destination rectangle
int hHeightDest, // height of destination rectangle
HDC hdcSrc, // handle to source DC
int nXOriginSrc, // x-coord of source upper-left corner
int nYOriginSrc, // y-coord of source upper-left corner
int nWidthSrc, // width of source rectangle
int nHeightSrc, // height of source rectangle
UINT crTransparent // color to make transparent
);
原来是修改的目标HDC,让TransparentBlt 相当于执行失败,这就说明TransparentBlt 就是画的那个小衣服啰;为了验证想法的正确性,我将1000AE93处改成jmp试试,结果小衣服变成了如下图的样子:
说明这个就是画小衣服的地方了。
衣服虽然是去掉了,但多了一个灰块,那我们把这段nop掉(从1000AE95至1000AEB8)之后,界面会变成下面这样了:
说明还有其它程序调用这段call不能直接nop掉,再一次膜拜 CjwNull 大 的意识,在前一个call就把这个参数能干掉了。利害。
看来关键点还是在100215B3这之前的参数了,如果我们把这个call给nop掉试试(不用nop这个callr 压栈参数,因为下面有调整栈的代码);会发现程序给直接挂了,不知道原因,也没有仔细去找挂的原因(水平有限),看来还只是按照 CjwNull 大 的办法去改push的参数了, CjwNull 大说只用改两个push,但是我下的最新版的要改三个参数,如果按 CjwNull 大的只改两处的话,当设置玻璃效果时那个小衣服又会出现,不设置玻璃效果不会出现,这三处是:1000F36F 52 push edx
10005059 55 push ebp
100215B2 55 push ebp
将以上三处改成push eax 就可以了;
实际上还有一个更简单的办法,我们发现TransparentBlt,会提示要画的高度和宽度,我们只要把那个衣服的高度或宽度改成0则相当于没有画了,经过上面的分析,我们实际上已经知道了地址1002CA94和1002CA98存放的是衣服的高度和宽度了,我们只要将此处任意一个改为0就OK了。细心的朋友可以更进一步分析一下,在SkinH.dll未调用DLLMain之前这处地址是为0,调用了DllMain之后这个地址的值才会被初使化为0x10,那么就是说如果想用这种办法的话非要SkinH.dll调用DllMain之后才行,也就是说最简单的办法就是可以在自己的程序里面打补丁(和 CjwNull 大打补丁的方法类似,只不过只要补丁一处就可以了)。
总结:破解skinsharp的三种方法:
1.将以下三处改为push eax1000F36F 52 push edx
10005059 55 push ebp
100215B2 55 push ebp
可以带壳破解,这样比较完美,不用脱壳,具体就是在1003A352 - E9 E19CFEFF jmp 10024038
这个地址处开始写补丁,然后 再跳转到入口点。
2.在自己程序里面打补丁,补丁掉1002CA94和1002CA98任意一处为0即可(注意有可能重定位)
3.按 CjwNull 大的方法在程序中补丁1中说明的三处
最后附上我自己写的一个类,可以将DLL文件放到资源中,从资源装载DLL的一个通过类,类封装得不好,望大家批评指正:
具体为:
声明一个全局变量
CDllFromMem abc;
然后从资源中装载DLL;相当于LoadLibrary()函数
abc.LoadLibraryFromRs(hInstance,"DLL",MAKEINTRESOURCE(IDR_DLL2));
最后得到所需函数和入口点,
typedef int (WINAPI *SkinHAttach)();
SkinHAttach SkinH_Attach;
SkinH_Attach=(SkinHAttach)abc.GetProcAddressFromRs("SkinH_attach"); //相当于GetProcAddress()函数了
最后就是调用啦,呵呵;
(*SkinH_Attach)();
我在类里面加了个PatchData();补丁函数,用来打补丁的,如果不用打补丁可以把这个函数删了,呵呵!就这些了!
DllFromMem.rar
(2.78 KB, 下载次数: 280)
示例程序是用向导生成的hello word程序,然后自己把动态链接库加入到了资源中
附件:
SkinSharpTest.rar
(168.93 KB, 下载次数: 478)
|