某CHM文件生成器的注册解码分析 by GGLHY
本帖最后由 GGLHY 于 2012-4-1 22:38 编辑某CHM文件生成器的注册解码分析 by GGLHY
想起论坛的echo兄给出了这个软件的内存注册机帖子(https://www.chinapyg.com/viewthread.php?tid=59513&extra=page%3D1)的时候,我当时大致看了下这个软件的算法但没深究(凌晨3点多,呵呵头昏脑胀的也懒得继续),正好下午难得有点空闲,OD了下,于是有了这篇破文。
【初涉算法,如有错误还望大牛指正!谢谢!】
直奔主题,来到:
005E5441 E8 52F9F6FF call 00554D98
005E5446 8B45 9C mov eax, dword ptr
005E5449 8B55 FC mov edx, dword ptr
005E544C E8 EBC8FDFF call 005C1D3C ; 看看这里和下面的标志位比较,经典的比较句式!Let`s F7
///////////////////////////////////////////////////////////////////////////////////////////////////////////
005C1D3C 55 push ebp
005C1D3D 8BEC mov ebp, esp
005C1D3F B9 04000000 mov ecx, 4
005C1D44 6A 00 push 0
005C1D46 6A 00 push 0
005C1D48 49 dec ecx
005C1D49^ 75 F9 jnz short 005C1D44
( ...省略部分代码...)
005C1D68 E8 53FCFFFF call 005C19C0
005C1D6D 8D55 EC lea edx, dword ptr
005C1D70 8B45 F0 mov eax, dword ptr ; 机器码到EAX
005C1D73 E8 C0FCFFFF call 005C1A38 ; 呵呵,这里有宝贝哦!F7(算法核心部分)
/////////////////////////////////////////////////////////////////////////////////////////////
005C1A38 55 push ebp
005C1A39 8BEC mov ebp, esp
005C1A3B 83C4 88 add esp, -78
005C1A3E 53 push ebx
005C1A3F 56 push esi
005C1A40 57 push edi
005C1A41 33C9 xor ecx, ecx
005C1A43 894D 88 mov dword ptr , ecx
005C1A46 894D F4 mov dword ptr , ecx
005C1A49 8955 F8 mov dword ptr , edx
005C1A4C 8945 FC mov dword ptr , eax
005C1A4F 33C0 xor eax, eax
005C1A51 55 push ebp
005C1A52 68 071B5C00 push 005C1B07
005C1A57 64:FF30 push dword ptr fs:
005C1A5A 64:8920 mov dword ptr fs:, esp
005C1A5D 8B45 F8 mov eax, dword ptr
005C1A60 E8 AB30F9FF call 00554B10
005C1A65 8B45 FC mov eax, dword ptr ; 机器码GHJ63G53(本例)到EAX
005C1A68 E8 6333F9FF call 00554DD0
005C1A6D 8945 F0 mov dword ptr , eax ; 机器码长度,本例为8
005C1A70 837D F0 00 cmp dword ptr , 0 ; 机器码长度是否为0,是则跳则挂!
005C1A74 74 73 je short 005C1AE9
005C1A76 B9 01000000 mov ecx, 1 ; ECX=1,
005C1A7B 33DB xor ebx, ebx ; ebx=0
005C1A7D 8D75 8C lea esi, dword ptr
005C1A80 3B4D F0 cmp ecx, dword ptr ; 机器码位置指针S:机器码长度指针i
005C1A83 7E 05 jle short 005C1A8A ; 机器码位置指针S超过机器码长度指针i后则初始化为1
005C1A85 B9 01000000 mov ecx, 1
005C1A8A 8B45 FC mov eax, dword ptr ; 机器码GHJ63G53
005C1A8D 0FB67C08 FF movzx edi, byte ptr ; 依次取机器码ASC到EDI
005C1A92 8BC7 mov eax, edi ; 所取机器码ASC到eax
005C1A94 99 cdq
005C1A95 F7F9 idiv ecx ; 依次取机器码ASC / 机器码位置指针S
005C1A97 8BC2 mov eax, edx ; 余数到EAX
005C1A99 8BD3 mov edx, ebx ; ebx初始为0,每循环1次+1,看做循环指针k
005C1A9B 0FAFD7 imul edx, edi ; 循环指针k * 所取机器码的ASC,积到EDX
005C1A9E 03C2 add eax, edx ; 积 + 余数
005C1AA0 2BC3 sub eax, ebx ; 和 - 循环指针k
005C1AA2 03C1 add eax, ecx ; 差 + 机器码位置指针S
005C1AA4 BF 18000000 mov edi, 18 ; EDI=18h=24
005C1AA9 99 cdq
005C1AAA F7FF idiv edi ; 和/18h=24
005C1AAC 8916 mov dword ptr , edx ; 保存余数到
005C1AAE 41 inc ecx ; ecx + 1
005C1AAF 43 inc ebx ; ebx + 1
005C1AB0 83C6 04 add esi, 4
005C1AB3 83FB 19 cmp ebx, 19 ; 与25比较(即机器码循环取到25位为止)
005C1AB6^ 75 C8 jnz short 005C1A80
005C1AB8 BB 19000000 mov ebx, 19 ; 循环结束后得到的结果,设为Y。本例为:010107150E010B0109110F0D06091311110917051611030901
005C1ABD 8D75 8C lea esi, dword ptr
005C1AC0 8D45 88 lea eax, dword ptr
005C1AC3 8A16 mov dl, byte ptr ; 依次将上面每次循环得到的结果放 到DL
005C1AC5 80C2 41 add dl, 41 ; +41(65)
005C1AC8 E8 2B32F9FF call 00554CF8
005C1ACD 8B55 88 mov edx, dword ptr ; 相加的结果到EDX,输出对应ASC的字符
005C1AD0 8D45 F4 lea eax, dword ptr
005C1AD3 E8 0033F9FF call 00554DD8
005C1AD8 83C6 04 add esi, 4
005C1ADB 4B dec ebx
005C1ADC^ 75 E2 jnz short 005C1AC0
005C1ADE 8B45 F8 mov eax, dword ptr
005C1AE1 8B55 F4 mov edx, dword ptr ; 真码到EDX
005C1AE4 E8 7B30F9FF call 00554B64
005C1AE9 33C0 xor eax, eax
005C1AEB 5A pop edx
005C1AEC 59 pop ecx
005C1AED 59 pop ecx
005C1AEE 64:8910 mov dword ptr fs:, edx
005C1AF1 68 0E1B5C00 push 005C1B0E
005C1AF6 8D45 88 lea eax, dword ptr
005C1AF9 E8 1230F9FF call 00554B10
005C1AFE 8D45 F4 lea eax, dword ptr
005C1B01 E8 0A30F9FF call 00554B10
005C1B06 C3 retn
/////////////////////////////////////////////////////////////////////////////////////////
005C1D78 8B45 EC mov eax, dword ptr ; 真码
005C1D7B 8BD3 mov edx, ebx ; 假码
005C1D7D E8 9A31F9FF call 00554F1C
005C1D82 0F85 29010000 jnz 005C1EB1 ; 跳还是不跳?这算不算个问题呢?呵呵
005C1D88 B2 01 mov dl, 1
005C1D8A A1 1C505700 mov eax, dword ptr
( ...省略部分代码...)
005C1DE0 50 push eax
005C1DE1 8D55 E4 lea edx, dword ptr
005C1DE4 B8 E81E5C00 mov eax, 005C1EE8 ; ASCII "user"
005C1DE9 E8 26F4FFFF call 005C1214
005C1DEE 8B55 E4 mov edx, dword ptr
005C1DF1 8B45 F8 mov eax, dword ptr
005C1DF4 59 pop ecx
005C1DF5 E8 5E39FBFF call 00575758
( ...省略部分代码...)
005C1EBE 8D45 DC lea eax, dword ptr
005C1EC1 BA 07000000 mov edx, 7
005C1EC6 E8 692CF9FF call 00554B34
005C1ECB C3 retn
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
005E5451 84C0 test al, al ;标志位
005E5453 74 34 je short 005E5489 ;传说中的关键跳!!!
005E5455 68 40000400 push 40040
005E545A 68 E0545E00 push 005E54E0 ; ASCII "鄀鏮C"
( ...省略部分代码...)
005E547C 50 push eax
005E547D 68 FFFF0000 push 0FFFF
005E5482 E8 D927F7FF call <jmp.&user32.SendNotifyMess>
005E5487 EB 16 jmp short 005E549F
005E5489 68 10000400 push 40010
005E548E 68 E0545E00 push 005E54E0 ; ASCII "鄀鏮C"
005E5493 68 6C555E00 push 005E556C
005E5498 6A 00 push 0
005E549A E8 1127F7FF call <jmp.&user32.MessageBoxW> ; 出错框!出错啦~~~
005E549F 33C0 xor eax, eax
005E54A1 5A pop edx
*************************************************************************************************************************
呵呵,算法总结:
0.与用户名无关。
1.机器码决定机器码长度指针i。
2.循环指针k表示初始值为0,每循环1次+1直到24为止。
3.依次取机器码的ASC / S,(比如取机器码:GHJ63G53的第一个“G”时,其ASC码为47,其位置指针S为1,(这里可以理解为G在第1位))
所得的余数 + (k * 所取机器码的ASC)- k + S,得到的和设为Q
Q / 18h 取其余数
4.Q / 18h的余数 + 41 得到的和作为ASC,输出对应的字符,相连得到25位字符,每5位1组,共5组即为注册码。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
说明:
机器码长度指针i:(比如本例中机器码:GHJ63G53,其长度指针为8)
机器码位置指针S:这与机器码长度指针i有点关系。其实就是所取机器码字符在机器码中的位置值。比如:机器码:GHJ63G53中,“6”的位置指针为4。且位置指针S不大于i
循环指针k:0-24,每循环1次,其值+1
循环指针所表示的值即当前循环指针数值。(比如循环到第2次时,其值为2)
*************************************************************************************************************************
本例中机器码:GHJ63G53,长度指针为8,但循环指针最大可到24(0~24)共25次,当GHJ63G53依次取完并运算后(即长度指针为8后),又重新取机器码GHJ63G53开始运算,(重新开始时,机器码长度指针再次从1开始,到8结束),这样一直运行到循环指针=24时为止。
呵呵,说半天还不如举个例子来得直接明了:
(为方便理解特用彩色标识:蓝色的是当前取机器码字符的的ASC,暗红色是位置指针,红色是余数,黑色的是循环指针)
比如说,循环指针k=7时,机器码位置指针=8。这时所取的机器码为最后一位“3”,其ASC为33。
33 / 8 得到其余数为3 ///取机器码GHJ63G53中的最后1个“3”的ASC码33 除以 这个“3”在机器码中的位置值8(S)
3(余数)+ ((7 * 33 ) - 7 + 8) = Q = 169 ///169(16进制) = 361(10进制)
169 / 18 = 0E + 1 ///余数为1
1 + 41 = 42 ///看做ASC码
哈哈,我们随便找个ASC表来看看,41对应的字符为"A",那么42对应的就是"B"了
接下来,循环指针k=8时,所取的机器码中的字符的其位置指针=1,(因为机器码已经取完了,这时机器码重新开始计算),所取的应该是重新开始的机器码GHJ63G53中的第一个“G”...
直至循环指针k=24为止。
换句话说,在外循环指针从0-24的循环过程中,机器码复制并相连直到25位,每机器码长度位(我这里是8位)作为内循环指针(1~8),共循环25/8 = 4 + 1 次;且位置指针从1~8后再循环,一直循环到K=24为止。
附本机注册信息:
机器码:GHJ63G53
这样够直观了吧,呵呵
G H J 6 3G 5 3 G HJ 6 3 G 53 G H J 63 G 5 3 G <------------------机器码复制并相连直到25位为止
S:1--------------8 1---------------8 1------------8 1 - <---|位置指针
. . . . .. . . . .. . . . .. . . . .. . . . . <---|
k 0--------------------------------------------------24 <---|循环指针
. . . . .. . . . .. . . . .. . . . .. . . . . <-------------算法过程
010107150E 010B010911 0F0D060913 1111091705 1611030901 <------------------Y
+ 41("A")
------------------------------------------------------------------------------------------------------------------------
B B H V OB L B J RP N G J TR R J X FW R D J B <==================注册码
又见好文,学习下, 请月大指点..../:001 005C1D82 0F85 29010000 jnz 005C1EB1 ; 跳还是不跳?这算不算个问题呢?呵呵
这句有意思,哈哈 月大好!:handshake
呵呵,写得有点仓促。还请各位大牛不吝指教! 月大好!
呵呵,写得有点仓促。还请各位大牛不吝指教!
GGLHY 发表于 2010-10-22 19:32 https://www.chinapyg.com/images/common/back.gif
我是来学习的哟 嘿嘿,跟你学习下算法/:001 嘿嘿,跟你学习下算法
echo 发表于 2010-10-23 22:13 https://www.chinapyg.com/images/common/back.gif
共同学习!:handshake 本帖最后由 whdl 于 2010-10-26 12:24 编辑
弱者前来学习。
多谢好文。感谢作者。 弱者前来学习。
多谢好文。感谢作者。
whdl 发表于 2010-10-26 12:22 https://www.chinapyg.com/images/common/back.gif
互相学习,共同进步!:handshake
页:
[1]
2