IP_tools2.06加密算法揭秘 ,雁南飞老兄务请一进,呵呵 (30千字)
IP_TOOLS2.06加密算法揭密几周前看见坛子上在讨论IP_TOOLS2.06,本菜鸟对IP工具较感兴趣,就想拿来试试手,happy一下。
谁知试了一周,花了n个小时(n>40),晕菜无数次,都没搞定,只好走人咯,郁闷啊!这阵放假,
本想再试试,整理些资料就算了,没想到竟还大致搞明白了,晕倒!(由于这个破程序n郁闷本菜
鸟,本菜不禁多吐了些苦水,各位老兄还请多包涵啊:))好吧,言归正传,下面我们开始吧:)
这个文件注册失败会弹出消息框,偶就想用MessageBox,MessageboxEx以及生成消息框,对话框的那
些API来拦截,没想到都栏不到,郁闷偶半天。后来用VC的SPY++看(softice中用hwnd应该也能看得
来),才发现IP_tools中的对话框消息框大多使用他们自己开发的类如TRegisterDlg,TRegisterDlg2,
TMessageForm, 而不是windows自带的Dialog类。乖乖,敌人的做工还很细噢,菜鸟很佩服的恨恨的说。
(如果有时间,研究一下如何自定义窗口类实现模式对话框消息框的效果倒是很有意思)
用CreateWindowExa倒是可以拦下,不过好像有点怪,菜鸟没有继续,就改拦截HMEMCPY了。
windows 9X下,HMemcpy是在16bit保护模式运行,被拦截下时的ES寄存器是目的地址的段selector,
通过softice的GDT ****查看该段的详细信息,段的初始地址就是32位下的目的地址。对这个
地址下bpm跟噢,很快程序就会被这个段点拦截下来,看一下是32位模式下的串拷贝,一般使
用ESI, EDI, 那就接着对EDI-1(或 2,4)(其实减不减都差不多啦)下bpm,继续跟啊。折腾了半天,
发现了程序进行计算和比较的地方了,算是取得了点阶段性的成果,呵呵。不过菜鸟到这花了7,8个小时,
菜啊,伤心噢。菜鸟使用用户名是happy, 密码是1112222,
注:
*本文中的数字都是16进制数
*文中有时指针与指针指向的值混用,不过应该能看出来什么时候是什么
下面看程序:
CODE:004AC629 mov eax, [ebp+var_10] // d eax, 看到用户名happy,
CODE:004AC62C call sub_49D94C //对用户名进行操作,返回加密后
的字串长度
CODE:004AC631 mov edi, eax
CODE:004AC633 lea edx, [ebp+var_10]
CODE:004AC636 mov eax, [esi]
CODE:004AC638 mov eax, [eax+1F4h]
CODE:004AC63E call sub_4236DC
CODE:004AC643 mov eax, [ebp+var_10] //d eax, 看到11112222
CODE:004AC646 call sub_49D9E8 //对密码进行操作
CODE:004AC64B cmp di, ax
CODE:004AC64E jnz loc_4AC7CA //到了4ac7ca我们就不happy了,
CODE:004AC654 mov eax, ds:off_4E128C //4e128c中存放的是地址4e3434,
是用户名加密后的存放地址
CODE:004AC659 mov edx, 1FFh
CODE:004AC65E call sub_49D930 //对加密后的用户名计算
CODE:004AC663 mov edi, eax
CODE:004AC665 mov eax, ds:off_4E1190 //4e1190中存放的是地址4e3634,
是密码加密后的存放地址
CODE:004AC66A mov edx, 1FFh
CODE:004AC66F call sub_49D930 //对加密后的密码计算
CODE:004AC674 cmp edi, eax
CODE:004AC676 jnz loc_4AC7CA
CODE:004AC67C mov eax, ds:off_4E128C //这以下按双字比较 4e3434+7,
4e3634+7空间中的内容
CODE:004AC681 add eax, 7
CODE:004AC684 mov eax, [eax]
CODE:004AC686 mov edx, ds:off_4E1190
CODE:004AC68C add edx, 7
CODE:004AC68F cmp eax, [edx]
CODE:004AC691 jnz loc_4AC7CA
CODE:004AC697 lea edx, [ebp+var_8] //三次比较都成功了,注册成功的对
话框就跳出来了噢
。。。。。
CODE:004AC6D8 mov eax, offset aThankYouForReg ; "Thank you for registering IP-To"
//到这菜鸟才注意到这个字串,要是开始时就
查找这个子串也许省偶很多事噢,心痛心痛!
。。。。。。
CODE:004AC7CA mov eax, offset aSorryYourReg_0 ; "Sorry, your registration number or "
// game over 的字串!Go to hell!
CODE:004AC7CF call sub_444700
先看一下 int 49D930(int i, char *pChar), 该函数对 (pChar+0B)开始的字符窜按字求和, 长度为 i-0B (i=1ff)。
让我们看一下重要的两个call 49d94c,49d9e8.
*** 49d94c:
CODE:0049D94C push ebp
。。。。。。
CODE:0049D9A8 push eax
CODE:0049D9A9 push offset unk_4E3434
CODE:0049D9AE push ebx
CODE:0049D9AF push offset unk_4DCB62
CODE:0049D9B4 push offset unk_4DCC62
CODE:0049D9B9 call sub_49DFFA //加密的核心函数
CODE:0049D9BE movsx eax, al
。。。。。。
CODE:0049D9D8 retn
CODE:0049D9D8 sub_49D94C endp ; sp = -210h
*** 49d9e8:
CODE:0049D9E8 push ebp
CODE:0049D9E9 mov ebp, esp
CODE:0049D9EB add esp, 0FFFFFDFCh
CODE:0049D9F1 push ebx
CODE:0049D9F2 mov [ebp+var_4], eax
CODE:0049D9F5 mov eax, [ebp+var_4]
CODE:0049D9F8 call sub_4040FC
CODE:0049D9FD xor eax, eax
CODE:0049D9FF push ebp
CODE:0049DA00 push offset loc_49DA62
CODE:0049DA05 push dword ptr fs:[eax]
CODE:0049DA08 mov fs:[eax], esp
CODE:0049DA0B lea edx, [ebp+var_204]
CODE:0049DA11 mov ecx, 1FFh
CODE:0049DA16 mov eax, [ebp+var_4]
CODE:0049DA19 call sub_49D880 //将输入密码当作16进制数解读,
如‘11112222’被转换成4个字节:
11 11 22 22,称之为密码1
CODE:0049DA1E lea eax, [ebp+var_204]
CODE:0049DA24 push eax
CODE:0049DA25 push offset unk_4E3634
CODE:0049DA2A mov eax, [ebp+var_4]
CODE:0049DA2D call sub_403F48 //计算密码1的字节长度
CODE:0049DA32 sar eax, 1 //计算密码1的字长度
CODE:0049DA34 jns short loc_49DA39
CODE:0049DA36 adc eax, 0
CODE:0049DA39
CODE:0049DA39 loc_49DA39: ; CODE XREF: sub_49D9E8+4Cj
CODE:0049DA39 push eax
CODE:0049DA3A push offset unk_4DCD66
CODE:0049DA3F push offset unk_4DCE66
CODE:0049DA44 call sub_49DFFA //核心加密算法
CODE:0049DA49 movsx ebx, al
CODE:0049DA4C xor eax, eax
CODE:0049DA4E pop edx
CODE:0049DA4F pop ecx
CODE:0049DA50 pop ecx
CODE:0049DA51 mov fs:[eax], edx
CODE:0049DA54 push offset loc_49DA69
CODE:0049DA59
CODE:0049DA59 loc_49DA59: ; CODE XREF: CODE:0049DA67j
CODE:0049DA59 lea eax, [ebp+var_4]
CODE:0049DA5C call sub_403CCC
CODE:0049DA61 retn
CODE:0049DA61 sub_49D9E8 endp ; sp = -210h
看到这,菜鸟就发晕了,用户名和密码1竟然都用相同算法(49dffa)加密,再比较其加密后的值,这不是要
搞出逆算法才行吗?过分啊!
下面看 一下49dffa的参数:
sub_49dffa(char * pBuffToCode, char *pDestBuff, int iLenBuffToCode, char *pBuff, char *pLongIntZ)
当进行用户名加密时是:
sub_49dffa('happy', 4e3434, 5, 4dcb62,4dcc62)
当进行密码1加密时是:
sub_49dffa( '11 11 22 22', 4e3634, 4, 4dcd66, 4dce66)
其中4dce66空间算装内容与4dcc62完全相同,长度为50h个字节。4dcd66与4dcb62空间内容不同。
下面我们进 49dffa去看:
sub_49dffa(char * pBuffToCode, char *pDestBuff, int iLenBuffToCode, char *pBuff, char *pLongIntZ)
CODE:0049DFFA push ebp
CODE:0049DFFB mov ebp, esp
CODE:0049DFFD push ebx
CODE:0049DFFE push esi
CODE:0049DFFF mov esi, [ebp+arg_0]
CODE:0049E002 mov ebx, [ebp+arg_8]
CODE:0049E005 push esi
CODE:0049E006 call sub_49F121 //返回pLoingIntZ指向字串的bit数,
从pLongIntZ+2a*2的字的高比特往下
找第一个非零bit位,这里返回280
CODE:0049E00B pop ecx
CODE:0049E00C add eax, 7
CODE:0049E00F sar eax, 3 //计算修正后pLongIntZ字节数,50
CODE:0049E012 movzx edx, bx
CODE:0049E015 cmp eax, edx //比较iLenBuffTocode与pLongIntZ长度,小等于则继续
//从算法角度来说,这个比较很有必要噢
CODE:0049E017 jge short loc_49E01E
CODE:0049E019 or eax, 0FFFFFFFFh
CODE:0049E01C jmp short loc_49E055
CODE:0049E01E ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049E01E
CODE:0049E01E loc_49E01E: ; CODE XREF: sub_49DFFA+1Dj
CODE:0049E01E push ebx
CODE:0049E01F push offset unk_4E3838
CODE:0049E024 push [ebp+arg_10]
CODE:0049E027 call sub_49DF4D //将pBufTofCode 拷到4e3838
CODE:0049E02C add esp, 0Ch
CODE:0049E02F push esi
CODE:0049E030 push [ebp+arg_4]
CODE:0049E033 push offset unk_4E3838
CODE:0049E038 push offset unk_4E38B8
CODE:0049E03D call sub_49F15D //重点!
CODE:0049E042 add esp, 10h
CODE:0049E045 push [ebp+arg_C]
CODE:0049E048 push offset unk_4E38B8
CODE:0049E04D call sub_49DFBA
CODE:0049E052 add esp, 8
CODE:0049E055
CODE:0049E055 loc_49E055: ; CODE XREF: sub_49DFFA+22j
CODE:0049E055 pop esi
CODE:0049E056 pop ebx
CODE:0049E057 pop ebp
CODE:0049E058 retn 14h
CODE:0049E058 sub_49DFFA endp
下面跟进sub_49f15d(char *pDest, char *pSource, char *pBuff, char *pLongIntZ)
pDest==4e38b8, pSource==4e3838 ;
pSource, pBuff, pLongIntZ说指向的数实际是超长正整数,和一般的32bit的正整数一样,低位在前,高位在后,
不同是的长度>4,输入参数最大字数只有28,是pLongIntZ的长度,从而决定操作字窜长度不超过28+2=2a,长度
值存在空间4dcf6a中。sub_49e386用来copy字串,copy字的长度一般是2a。
sub_49F15D proc near ; CODE XREF: sub_49DFFA+43p
CODE:0049F15D ; CODE:0049F3DEp ...
CODE:0049F15D
CODE:0049F15D var_88 = byte ptr -88h
CODE:0049F15D var_6 = word ptr -6
CODE:0049F15D var_4 = dword ptr -4
CODE:0049F15D pDest = dword ptr 8
CODE:0049F15D pSource = dword ptr 0Ch
CODE:0049F15D pBuff = dword ptr 10h
CODE:0049F15D pLongIntZ = dword ptr 14h
CODE:0049F15D
CODE:0049F15D push ebp
CODE:0049F15E mov ebp, esp
CODE:0049F160 add esp, 0FFFFFF78h
CODE:0049F166 push ebx
CODE:0049F167 push esi
CODE:0049F168 push edi
CODE:0049F169 mov ebx, [ebp+pLongIntZ]
CODE:0049F16C mov edi, [ebp+pBuff]
CODE:0049F16F mov esi, [ebp+pDest]
CODE:0049F172 push 1
CODE:0049F174 push esi
CODE:0049F175 call sub_49E3AC
CODE:0049F17A add esp, 8
CODE:0049F17D cmp word ptr [edi], 0 ;
CODE:0049F17D ;
CODE:0049F17D ;
CODE:0049F181 jnz short loc_49F1B7 -->跳
。。。
CODE:0049F1B7 cmp word ptr [ebx], 0
CODE:0049F1BB jnz short loc_49F1D4 -->NZ, 跳
。。。
CODE:0049F1D4 movsx edx, ds:word_4DCF68 ;
CODE:0049F1D4 ;
CODE:0049F1DB cmp word ptr [ebx+edx*2-2], 0
CODE:0049F1E1 jge short loc_49F1ED --〉等0,跳
。。。
CODE:0049F1ED ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F1ED
CODE:0049F1ED loc_49F1ED: ; CODE XREF: sub_49F15D+84j
CODE:0049F1ED push ebx
CODE:0049F1EE push [ebp+pSource]
CODE:0049F1F1 call sub_49E2B7 //比较大小,pLongIntZ必须大等于pSource!
CODE:0049F1F6 add esp, 8
CODE:0049F1F9 test ax, ax
CODE:0049F1FC jl short loc_49F208
CODE:0049F1FE mov eax, 0FFFFFFFDh
CODE:0049F203 jmp loc_49F33C
CODE:0049F208 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F208
CODE:0049F208 loc_49F208: ; CODE XREF: sub_49F15D+9Fj
CODE:0049F208 push ebx
CODE:0049F209 push edi
CODE:0049F20A call sub_49E2B7 //比较大小,pLongIntZ必须大等于pBuff(why?)
CODE:0049F20F add esp, 8
CODE:0049F212 test ax, ax
CODE:0049F215 jl short loc_49F221
CODE:0049F217 mov eax, 0FFFFFFFCh
CODE:0049F21C jmp loc_49F33C
CODE:0049F221 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F221
CODE:0049F221 loc_49F221: ; CODE XREF: sub_49F15D+B8j
CODE:0049F221 mov dx, ds:word_4DCF68
CODE:0049F228 mov [ebp+var_6], dx
CODE:0049F22C push ebx
CODE:0049F22D call sub_49F121 //计算pLongIntZ的bit数,=280,
CODE:0049F232 pop ecx
CODE:0049F233 add eax, 20h //为运算增加20bits,
CODE:0049F236 sar eax, 4 //计算需要的字数(280+20)/10
CODE:0049F239 mov ds:word_4DCF68, ax //4DCF68=2A
CODE:0049F23F push ebx
CODE:0049F240 call sub_49E8B3 //重要初始化!!!!!
CODE:0049F245 pop ecx
CODE:0049F246 test eax, eax
CODE:0049F248 jz short loc_49F25F --〉跳
CODE:0049F24A mov cx, [ebp+var_6]
。。。
CODE:0049F25F ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F25F
CODE:0049F25F loc_49F25F: ; CODE XREF: sub_49F15D+EBj
CODE:0049F25F push edi
CODE:0049F260 call sub_49E3DB //计算pBuff所指向的空间的最高非零字的位置
CODE:0049F265 pop ecx
CODE:0049F266 test ax, ax
CODE:0049F269 jnz short loc_49F272 --〉nz, 跳
CODE:0049F26B xor eax, eax
CODE:0049F26D jmp loc_49F33C
CODE:0049F272 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F272
CODE:0049F272 loc_49F272: ; CODE XREF: sub_49F15D+10Cj
CODE:0049F272 movsx edx, ax
CODE:0049F275 shl edx, 4
CODE:0049F278 mov [ebp+var_4], edx ebp+var_4初始存放pBuff有效bit数,
CODE:0049F27B movsx ecx, ax
CODE:0049F27E add ecx, ecx
CODE:0049F280 add edi, ecx
CODE:0049F282 add edi, 0FFFFFFFEh //移pBuff高位的第一个字到edi,
CODE:0049F285 mov bx, 8000h
CODE:0049F289 jmp short loc_49F291
CODE:0049F28B ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F28B
CODE:0049F28B loc_49F28B: ; CODE XREF: sub_49F15D+137j
CODE:0049F28B shr bx, 1
CODE:0049F28E dec [ebp+var_4]
CODE:0049F291
CODE:0049F291 loc_49F291: ; CODE XREF: sub_49F15D+12Cj
CODE:0049F291 test [edi], bx
CODE:0049F294 jz short loc_49F28B
CODE:0049F296 dec [ebp+var_4] //找到了第一个非零bit,当前bit位数减一
CODE:0049F299 push [ebp+pSource]
CODE:0049F29C push esi
CODE:0049F29D call sub_49E386 //用 pSource 初始化 pDes
CODE:0049F2A2 add esp, 8
CODE:0049F2A5 shr bx, 1
CODE:0049F2A8 test bx, bx
CODE:0049F2AB jnz short loc_49F30E --〉跳
CODE:0049F2AD mov bx, 8000h
CODE:0049F2B1 sub edi, 2
CODE:0049F2B4 jmp short loc_49F30E
CODE:0049F2B6 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049F2B6
CODE:0049F2B6 loc_49F2B6: ; CODE XREF: sub_49F15D+1BAj
CODE:0049F2B6 push esi
CODE:0049F2B7 push esi
CODE:0049F2B8 lea eax, [ebp+var_88]
CODE:0049F2BE push eax
CODE:0049F2BF call sub_49E94F //call sub_49e94f(tempBuf, pDest,pDest);!!!!!
CODE:0049F2C4 add esp, 0Ch
CODE:0049F2C7 lea edx, [ebp+var_88]
CODE:0049F2CD push edx
CODE:0049F2CE push esi
CODE:0049F2CF call sub_49E386 //copy tempBuf到 pDest
CODE:0049F2D4 add esp, 8
CODE:0049F2D7 test [edi], bx //pBuff当前bit位的值是否为1?
CODE:0049F2DA jz short loc_49F2FF
CODE:0049F2DC push [ebp+pSource] //=1继续
CODE:0049F2DF push esi
CODE:0049F2E0 lea ecx, [ebp+var_88]
CODE:0049F2E6 push ecx
CODE:0049F2E7 call sub_49E94F //call sub_49e94f(tempBuf, pDest, pSource);!!!!
//这里竟然还有pSource作参数,菜鸟一度晕菜!
CODE:0049F2EC add esp, 0Ch
CODE:0049F2EF lea eax, [ebp+var_88]
CODE:0049F2F5 push eax
CODE:0049F2F6 push esi
CODE:0049F2F7 call sub_49E386 //copy tempBuf到 pDest
CODE:0049F2FC add esp, 8
CODE:0049F2FF
CODE:0049F2FF loc_49F2FF: ; CODE XREF: sub_49F15D+17Dj
CODE:0049F2FF shr bx, 1 //bx移位
CODE:0049F302 test bx, bx
CODE:0049F305 jnz short loc_49F30E
CODE:0049F307 mov bx, 8000h
CODE:0049F30B sub edi, 2 //edi指向pBuff的当前字
CODE:0049F30E
CODE:0049F30E loc_49F30E: ; CODE XREF: sub_49F15D+14Ej
CODE:0049F30E ; sub_49F15D+157j ...
CODE:0049F30E mov eax, [ebp+var_4]
CODE:0049F311 add [ebp+var_4], 0FFFFFFFFh //当前bit位减一
CODE:0049F315 test eax, eax //遍历完pBuff?
CODE:0049F317 jnz short loc_49F2B6 --〉no则跳
CODE:0049F319 push 0
CODE:0049F31B lea edx, [ebp+var_88]
CODE:0049F321 push edx
CODE:0049F322 call sub_49E3AC
CODE:0049F327 add esp, 8
CODE:0049F32A call sub_49F0DA
CODE:0049F32F mov cx, [ebp+var_6]
CODE:0049F333 mov ds:word_4DCF68, cx
CODE:0049F33A xor eax, eax
CODE:0049F33C
CODE:0049F33C loc_49F33C: ; CODE XREF: sub_49F15D+4Ej
CODE:0049F33C ; sub_49F15D+55j ...
CODE:0049F33C pop edi
CODE:0049F33D pop esi
CODE:0049F33E pop ebx
CODE:0049F33F mov esp, ebp
CODE:0049F341 pop ebp
CODE:0049F342 retn
CODE:0049F342 sub_49F15D endp
CODE:0049F342
这里有两个call,sub_49E8B3 和 sub_49e94f。
先看sub_49e8b3, 首先将pLongIntZ的地址存入4DD76C+0。4dd76c+4开始的空间存放了16个地址,
那些地址指向的空间用来存放pLongIntZ*2^n (n=1到16), 把pLongIntZ*2^n(n=0到16)的
最高字节存到4DD7B0+2*n, 把pLongIntZ*2^n(n=0到16)的次高字节存到4DD7D2+2*n, 便于
后面比较大小时使用。
sub_49e94f, 是最核心的函数了,好长啊,从49e94f到49f0d9,好在结构还比较简单,呵呵
来看sub_49e94f(char *pTempDest, char *pLongIntX, char *pLongIntY)
CODE:0049E94F sub_49E94F proc near ; CODE XREF: sub_49F15D+162p
CODE:0049E94F ; sub_49F15D+18Ap
CODE:0049E94F
CODE:0049E94F var_6 = word ptr -6
CODE:0049E94F var_4 = dword ptr -4
CODE:0049E94F arg_0 = dword ptr 8
CODE:0049E94F arg_4 = dword ptr 0Ch
CODE:0049E94F arg_8 = dword ptr 10h
CODE:0049E94F
CODE:0049E94F push ebp
CODE:0049E950 mov ebp, esp
CODE:0049E952 add esp, 0FFFFFFF8h
CODE:0049E955 push ebx
CODE:0049E956 push esi
CODE:0049E957 push edi
CODE:0049E958 mov edi, [ebp+arg_8]
CODE:0049E95B mov ebx, [ebp+arg_0]
CODE:0049E95E push [ebp+arg_4]
CODE:0049E961 push offset dword_4DDF74
CODE:0049E966 call sub_49E872 //该函数首先将pLongIntX的地址存入4ddf74。
4ddf74+4开始的15个DW空间存放地址,这些地
址指向的空间的值为 pLongIntX*2^n,n=1到15
CODE:0049E96B add esp, 8
CODE:0049E96E movsx eax, ds:word_4DCF68
CODE:0049E975 add eax, eax
CODE:0049E977 add eax, ebx
CODE:0049E979 add eax, 0FFFFFFFEh
CODE:0049E97C mov [ebp+var_4], eax //ebp+var4保存pTempDest的最高字地址
CODE:0049E97F mov esi, [ebp+var_4]
CODE:0049E982 sub esi, 2 //esi保存pTempDest次高字地址
CODE:0049E985 push 0
CODE:0049E987 push ebx
CODE:0049E988 call sub_49E3AC //初始化ptempDest指向的空间为0
CODE:0049E98D add esp, 8
CODE:0049E990 push edi
CODE:0049E991 call sub_49E3DB //计算pLongIntY的字长
CODE:0049E996 pop ecx
CODE:0049E997 mov [ebp+var_6], ax //pLongIntY字长存入ebp+bar_6
CODE:0049E99B cmp [ebp+var_6], 0
CODE:0049E9A0 jnz short loc_49E9A9 -->nz跳
CODE:0049E9A2 xor eax, eax
CODE:0049E9A4 jmp loc_49F0D3
CODE:0049E9A9 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049E9A9
CODE:0049E9A9 loc_49E9A9: ; CODE XREF: sub_49E94F+51j
CODE:0049E9A9 movsx edx, [ebp+var_6]
CODE:0049E9AD add edx, edx
CODE:0049E9AF add edi, edx
CODE:0049E9B1 add edi, 0FFFFFFFEh //edi保存pLongIntY的当前字的地址
CODE:0049E9B4 jmp loc_49F0BF --〉跳
CODE:0049E9B9 ; 哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
CODE:0049E9B9
CODE:0049E9B9 loc_49E9B9: ; CODE XREF: sub_49E94F+77Cj
CODE:0049E9B9 push ebx
CODE:0049E9BA call sub_49E83C //将pTempDest移高一个字,也就是
将pTempDest*2^16(这步非常重要噢!)
CODE:0049E9BF pop ecx
CODE:0049E9C0 test byte ptr [edi+1], 80h //比较pLongIntY当前字的第15bit,
CODE:0049E9C4 jz short loc_49E9D7
CODE:0049E9C6 push 0
CODE:0049E9C8 push ds:off_4DDFB0 //ds:off_4DDFB0存有pLongIntX*2^15的指针
CODE:0049E9CE push ebx
CODE:0049E9CF call sub_49E199 //两超长正整数相加,存回pTempDest,
//字节间的进位处理还晃了本菜一下,呵
CODE:0049E9D4 add esp, 0Ch
CODE:0049E9D7
CODE:0049E9D7 loc_49E9D7: ; CODE XREF: sub_49E94F+75j
......
CODE:0049EB12
CODE:0049EB12 loc_49EB12: ; CODE XREF: sub_49E94F+1B0j
CODE:0049EB12 test byte ptr [edi], 1
CODE:0049EB15 jz short loc_49EB28
CODE:0049EB17 push 0
CODE:0049EB19 push ds:dword_4DDF74
CODE:0049EB1F push ebx
CODE:0049EB20 call sub_49E199
CODE:0049EB25 add esp, 0Ch
CODE:0049EB28
//以上对edi+1,和edi的各个非零比特,将pTempDest加上相应的pLongIntX*2^n
CODE:0049EB28 loc_49EB28: ; CODE XREF: sub_49E94F+1C6j
CODE:0049EB28 mov ecx, [ebp+var_4]
CODE:0049EB2B mov ax, [ecx] //ax=pTempDest的最高字的值
CODE:0049EB2E sub ax, ds:word_4DD7D0 //4dd7d0保存了 pLongIntZ*2^16
的最高字的值
CODE:0049EB35 test ax, ax
CODE:0049EB38 jg short loc_49EB6B //pTempDest大就跳到49eb6b
CODE:0049EB3A test ax, ax
CODE:0049EB3D jnz short loc_49EB7C
CODE:0049EB3F mov dx, [esi] //dx=pTempDest的次高字的值
CODE:0049EB42 cmp dx, ds:word_4DD7F2 //4dd7d0保存了 pLongIntZ*2^16
的次高字的值
CODE:0049EB49 ja short loc_49EB6B //pTempDest大就跳到49eb6b
CODE:0049EB4B mov cx, [esi]
CODE:0049EB4E cmp cx, ds:word_4DD7F2
CODE:0049EB55 jnz short loc_49EB7C //小于就跳过49eb6b
CODE:0049EB57 push ds:off_4DD7AC
CODE:0049EB5D push ebx
CODE:0049EB5E call sub_49E2B7 //比较pTempDest与pLongIntZ*2^16大小
CODE:0049EB63 add esp, 8
CODE:0049EB66 test ax, ax
CODE:0049EB69 jl short loc_49EB7C //小于就跳走
CODE:0049EB6B
CODE:0049EB6B loc_49EB6B: ; CODE XREF: sub_49E94F+1E9j
CODE:0049EB6B ; sub_49E94F+1FAj
CODE:0049EB6B push 0
CODE:0049EB6D push ds:off_4DD7AC
CODE:0049EB73 push ebx
CODE:0049EB74 call sub_49E1E6 //将pTempDest指向的值减去pLongIntZ*2^16
CODE:0049EB79 add esp, 0Ch
。。。。。。
CODE:0049F068
CODE:0049F068 loc_49F068: ; CODE XREF: sub_49E94F+6DAj
CODE:0049F068 ; sub_49E94F+6F2j ...
CODE:0049F068 mov eax, [ebp+var_4]
CODE:0049F06B mov ax, [eax]
CODE:0049F06E sub ax, ds:word_4DD7B0
CODE:0049F075 test ax, ax
CODE:0049F078 jg short loc_49F0AB
CODE:0049F07A test ax, ax
CODE:0049F07D jnz short loc_49F0BC
CODE:0049F07F mov dx, [esi]
CODE:0049F082 cmp dx, ds:word_4DD7D2
CODE:0049F089 ja short loc_49F0AB
CODE:0049F08B mov cx, [esi]
CODE:0049F08E cmp cx, ds:word_4DD7D2
CODE:0049F095 jnz short loc_49F0BC
CODE:0049F097 push ds:dword_4DD76C
CODE:0049F09D push ebx
CODE:0049F09E call sub_49E2B7
CODE:0049F0A3 add esp, 8
CODE:0049F0A6 test ax, ax
CODE:0049F0A9 jl short loc_49F0BC
CODE:0049F0AB
CODE:0049F0AB loc_49F0AB: ; CODE XREF: sub_49E94F+729j
CODE:0049F0AB ; sub_49E94F+73Aj
CODE:0049F0AB push 0
CODE:0049F0AD push ds:dword_4DD76C
CODE:0049F0B3 push ebx
CODE:0049F0B4 call sub_49E1E6
CODE:0049F0B9 add esp, 0Ch
//以上依次将pTempDest与pLongIntZ*2^n(n=16到0)比较大小,大等则将pTempDest减去pLongIntZ*2^n
//看出这实值是什么了吗?是将pTempDester mod(pLongIntZ)啊!!!
CODE:0049F0BC
CODE:0049F0BC loc_49F0BC: ; CODE XREF: sub_49E94F+72Ej
CODE:0049F0BC ; sub_49E94F+746j ...
CODE:0049F0BC sub edi, 2 //下移pLongIntY的当前字
CODE:0049F0BF
CODE:0049F0BF loc_49F0BF: ; CODE XREF: sub_49E94F+65j
CODE:0049F0BF mov ax, [ebp+var_6]
CODE:0049F0C3 add [ebp+var_6], 0FFFFh
CODE:0049F0C8 test ax, ax //pLongIntY的字都读完了吗?
CODE:0049F0CB jnz loc_49E9B9 --〉nz跳
CODE:0049F0D1 xor eax, eax
CODE:0049F0D3
CODE:0049F0D3 loc_49F0D3: ; CODE XREF: sub_49E94F+55j
CODE:0049F0D3 pop edi
CODE:0049F0D4 pop esi
CODE:0049F0D5 pop ebx
CODE:0049F0D6 pop ecx
CODE:0049F0D7 pop ecx
CODE:0049F0D8 pop ebp
CODE:0049F0D9 retn
CODE:0049F0D9 sub_49E94F endp
看出来sub_49e94f(char *ptempDest, char *pLongIntX, char *pLongIntY)做了什么吗?说出来
简单s了,就是 (*pTempDest)=((*pLongIntX)*(*pLongIntY))mod (*pLongIntZ)啊!具体推理
菜鸟就不写了,手写不动了啊:) 各位应该能推得出来,不然要加油噢。
哇,菜鸟到这快写完了噢,开心啊:) 各位是不是看得也有点累了?呵呵
OK! 快要胜利了噢,现在结合sub_49F15D伪代码来看看就究竟是怎么回事吧!
sub_49f15d(char *pDest, char *pSource, char *pBuff, char *pLongIntZ)
{
初始化pLongIntZ*2^n(n=1到16,其实可以认为n=0到16)
从高位到底位找到 pBuff的第一个非0比特位,初始化(*pDest)=(*pSource);
对此后从高到底的pBuff的每个比特位
{
sub_49e94f(tempBuf, pDest,pDest);!
(*pDest)=(*tempBuf);//这两行实际上是(*pDest)=(*pDest)^2 mod (*pLongIntZ);
if(当前bit位值==1)
{
sub_49e94f(tempBuf, pDest,pSource);!
(*pDest)=(*tempBuf);//这两行实际上是(*pDest)=(*pDest)*(*pSource) mod (*pLongIntZ);
这里的pSource前期一度让偶认为无法求出逆算法
}
}
}
实质上, 最终(*pDest)=(*pSource)^m mod (*pLongIntZ) , m是由pBuff决定的一个常数!偶用*pSorce=1
试了一下,(*pDest)果然等于1,哈哈。。。还试了一个*pSource=10, *pBuff=07, 这时
*Dest=00 00 00 10,perfect!哈!
对于偶的例子,就是要求
当
sub_49f15d(char *pDest1, "happy", 4dcb62, 4dcc62)
sub_49f15d(char *pDest2, '11 11 22 22', 4dcb66, 4dce66)
*4dcc62=*4dce66
时,要求
1)*pDest1的位数=*pDest2的位数,
2)*pDest1的第8位开始的DW等于*pDest2的第8位开始的DW。
3)*pDest1的第0B位开始的字节和等于*pDest2的第0B位开始的字节和。
嗯,一切都很明了了吧!可是对于 x^m mod Z =y, m,Z常数,知道y,怎么求x? 菜鸟不会啊!应该有什
么公式吧?不知道和RSA算法有没有什么关系?不过,本菜鸟被这破程序折腾得够呛啊,实在是不想再动了。好
了,就到这里吧!IP_TOOLS,go to hell!呵呵。。。这是本菜第一次写关于破解的东东,没有什么经
验,希望各位没有看得晕菜过去噢,呵
半点星
02/02/13
