好友
阅读权限 40
听众
最后登录 1970-1-1
想去睡觉了,临睡觉前再发个以前的东东,这个比较简单,用IDA 分析的,没有调式过,估计用OD更简单吧,大牛飘过,跟我一样菜的朋友能进来指点一下!
正文如下:
不知道CM的分析应该发到哪个版块,本来以为是CM和RM的那个版块,可是上面写的是活动版块,不敢乱发,就发到这个我比较熟悉的版块吧,如果发错位置了,就麻烦斑斑大哥代劳转移一下!谢谢!
首先感谢PPT同学给我了这个CM,很有意思,它的具体要求如下:
Hi! There!..It's my first keygenme (crackme). Here are some tasks you should do:
-------------------------------------------------------------------------
1. To start searching a key for your name, you need to patch something to enter
more than 1 symbol, (Patch it to 80 symbols) (no jne, je, & etc jump patching.)
2. Find key generator solution, and write a keygen
3. Patch it, to stop closing after the registration procedure
(not allowed to patch jne, je, & etc "jump patching". (e.g: "jne" -> "je")
-------------------------------------------------------------------------
Exe file is not protected, and it is very easy to find key & to write a
keygen. But no built-in keygens (injections). As u can see I made it for newbies...
__________________
P.s: Don't forget what i said: "no jump patching". :)
Have fun!!! ;) THanx to crackmes.de
好了,不多说了,进入正题,应该说这个CM确实很容易,完全的明码,根本没有隐藏!很适合象我这样的新人!而且它也确实很有意思!
刚拿到这个CM的时候,直接用OD打开,这个小程序基本上就一目了然了!顺手在GetDlgItemTextA上F2,F9,可是他居然断不下来!
基本上到了DialogBoxParamA这个函数就飞了……
想必没有人会不知道DialogBoxParamA这个函数是干什么的吧!
用资源编辑器找到两个文本框的ID:1001,1002,转换成HEX就是3E9,3EA.text: 0040102E
.text: 0040102E
.text: 0040102E
.text: 0040102E
.text: 0040102E
.text: 0040102E DialogFunc proc near
.text: 0040102E
.text: 0040102E hDlg = dword ptr 8
.text: 0040102E arg_4 = dword ptr 0Ch
.text: 0040102E arg_8 = dword ptr 10h
.text: 0040102E
.text: 0040102E push ebp
.text: 0040102F mov ebp , esp
.text: 00401031 mov eax , [ebp +arg_4]
.text: 00401034 cmp eax , 110h
.text: 00401039 jnz short loc_401089
.text: 0040103B mov eax , [ebp +hDlg]
.text: 0040103E mov hDlg, eax
.text: 00401043 push 3E9h
.text: 00401048 push [ebp +hDlg]
.text: 0040104B call GetDlgItem
.text: 00401050 mov hWnd, eax
.text: 00401055 xor eax , eax
.text: 00401057 push 3EAh
.text: 0040105C push [ebp +hDlg]
.text: 0040105F call GetDlgItem
.text: 00401064 mov dword_403210, eax
.text: 00401069 xor eax , eax
.text: 0040106B call sub_40130D
.text: 00401070 push 13h
.text: 00401072 push 0
.text: 00401074 push 0
.text: 00401076 push 0
.text: 00401078 push 0
.text: 0040107A push 0FFFFFFFFh
.text: 0040107C push [ebp +hDlg]
.text: 0040107F call SetWindowPos
.text: 00401084 jmp loc_401271
GetDlgItem到两个文本框以后,都会跟进.text:0040106B call sub_40130D 这个函数里面去
我们也进去看看吧~.text: 0040130D
.text: 0040130D
.text: 0040130D
.text: 0040130D sub_40130D proc near
.text: 0040130D push eax
.text: 0040130E xor eax , eax
.text: 00401310 mov eax , hDlg
.text: 00401315 push 0
.text: 00401317 push 1
.text: 00401319 push 0C5h
.text: 0040131E push 3E9h
.text: 00401323 push eax
.text: 00401324 call SendDlgItemMessageA
.text: 00401329 xor eax , eax
.text: 0040132B mov eax , hDlg
.text: 00401330 push 0
.text: 00401332 push 1
.text: 00401334 push 0C5h
.text: 00401339 push 3EAh
.text: 0040133E push eax
.text: 0040133F call SendDlgItemMessageA
.text: 00401344 pop eax
.text: 00401345 retn
.text: 00401345 sub_40130D endp
看到了吧,这里向两个文本框发送消息了做文本个数的限制了,要取消它,就把上面的两个PUSH 1改成PUSH 50就OK了!
这样输入字符字数的限制就取消了!
再看取消信息提示后失败的方法,找到MessageBoxA我们来看看(它有两个MessageBoxA,我想大家不会找错的!).text: 0040111B
.text: 0040111B
.text: 0040111B loc_40111B:
.text: 0040111B
.text: 0040111B xor eax , eax
.text: 0040111D cmp ecx , 1
.text: 00401120 jnz short loc_401130
.text: 00401122 xor ecx , ecx
.text: 00401124 mov ecx , offset aCongratulation
.text: 00401129 mov eax , offset aWellDonePlease
.text: 0040112E jmp short loc_40113C
.text: 00401130
.text: 00401130
.text: 00401130 loc_401130:
.text: 00401130 xor ecx , ecx
.text: 00401132 mov eax , offset aSomethingWrong
.text: 00401137 mov ecx , offset aError__
.text: 0040113C
.text: 0040113C loc_40113C:
.text: 0040113C push 0
.text: 0040113E push ecx
.text: 0040113F push eax
.text: 00401140 push [ebp +hDlg]
.text: 00401143 call MessageBoxA
.text: 00401148 mov eax , 0
.text: 0040114D cmp eax , 0
.text: 00401150 jnz loc_401255
.text: 00401156 jmp loc_exit
我想大家在看到这个函数后面的代码的时候,谁都不会没有感觉的:.text: 00401148 mov eax , 0
.text: 0040114D cmp eax , 0
.text: 00401150 jnz loc_401255
这里的JNZ基本上就是被NOP掉了,怎么改才能让它正常也不用我说了吧,把赋值的0改成1就OK了~
好了,下面我们来分析一下他的这个程序的算法流程!.text: 004010F1 mov eax , offset aISaidItIsVeryE
.text: 004010F6 xor eax , eax
.text: 004010F8 xor ecx , ecx
.text: 004010FA xor ebx , ebx
.text: 004010FC xor edx , edx
.text: 004010FE
.text: 004010FE loc_4010FE:
.text: 004010FE inc ebx
.text: 004010FF push ebx
.text: 00401100 push hWnd
.text: 00401106 call GetWindowTextLengthA
.text: 0040110B xor ecx , ecx
.text: 0040110D mov ebx , eax
.text: 0040110F mov eax , offset Buffer
.text: 00401114 call sub_Name
.text: 00401119 jmp short loc_40115B
我们跟进这个sub_Name函数看看吧!{
.text: 004012D1
.text: 004012D1
.text: 004012D1
.text: 004012D1 sub_Name proc near
.text: 004012D1
.text: 004012D1 mov dl , [eax ]
.text: 004012D3 imul ecx , 48h
.text: 004012D6 sub ecx , edx
.text: 004012D8 sub ecx , 6Fh
.text: 004012DB mov edx , ecx
.text: 004012DD xor ecx , 0BACAFh
.text: 004012E3 inc eax
.text: 004012E4 dec ebx
.text: 004012E5 cmp ebx , 0
.text: 004012E8 jnz short sub_4012D1
.text: 004012EA retn
.text: 004012EA sub_Name endp
}
继续,我们来到loc_40115B来看一下.text: 0040115B
.text: 0040115B
.text: 0040115B loc_40115B:
.text: 0040115B pop ebx
.text: 0040115C cmp ebx , 2
.text: 0040115F jz short loc_401183
.text: 00401161 xor edx , edx
.text: 00401163 mov dword_403218, ecx
.text: 00401169 xor eax , eax
.text: 0040116B push offset pcbBuffer
.text: 00401170 push offset Buffer
.text: 00401175 call GetUserNameA
.text: 0040117A xor edx , edx
.text: 0040117C xor ecx , ecx
.text: 0040117E jmp loc_4010FE
:
好我们到loc_401183看看:; ---------------------------------------------------------------------------
.text :00401183
.text :00401183 loc_401183: ; CODE XREF: DialogFunc+131 j
.text :00401183 xor edx, edx
.text :00401185 mov dword_40321C, ecx
.text :0040118 B push dword_40321C
.text :00401191 push dword_403218
.text :00401197 call sub_40127A
来到sub_40127A,我不多注释了,大家可以边用OD跟这个CM边看我帖出来的代码,这里程序条理代码如下{
.text: 0040127A
.text: 0040127A
.text: 0040127A
.text: 0040127A
.text: 0040127A
.text: 0040127A sub_40127A proc near
.text: 0040127A
.text: 0040127A arg_0 = dword ptr 8
.text: 0040127A arg_4 = dword ptr 0Ch
.text: 0040127A
.text: 0040127A push ebp
.text: 0040127B mov ebp , esp
.text: 0040127D xor eax , eax
.text: 0040127F xor ebx , ebx
.text: 00401281 mov eax , [ebp +arg_0]
.text: 00401284 mov ebx , [ebp +arg_4]
.text: 00401287 mov edx , eax
.text: 00401289 xor edx , ebx
.text: 0040128B xor edx , 0FFACh
.text: 00401291 xor ebx , 553h
.text: 00401297 add eax , ebx
.text: 00401299 add ebx , edx
.text: 0040129B dec ebx
.text: 0040129C add eax , ebx
.text: 0040129E leave
.text: 0040129F retn 8
.text: 0040129F sub_40127A endp
.text: 0040129F
}
.text: 0040119C mov dword_403220, eax
.text: 004011A1 call sub_401346
{
.text: 00401346
.text: 00401346
.text: 00401346
.text: 00401346
.text: 00401346 sub_401346 proc near
.text: 00401346 mov eax , dword_40321C
.text: 0040134B mov ebx , dword_403218
.text: 00401351 cmp eax , ebx
.text: 00401353 jnz short locret_401363
.text: 00401355 xor ebx , 8Eh
.text: 0040135B add ebx , eax
.text: 0040135D mov dword_403218, ebx
.text: 00401363
.text: 00401363 locret_401363:
.text: 00401363 retn
.text: 00401363 sub_401346 endp
.text: 00401363
}
.text: 004011A6 push dword_40321C
.text: 004011AC push offset unk_403224
.text: 004011B1 call sub_4012A2
{
.text: 004012A2
.text: 004012A2
.text: 004012A2
.text: 004012A2
.text: 004012A2
.text: 004012A2 sub_4012A2 proc near
.text: 004012A2
.text: 004012A2
.text: 004012A2 arg_0 = dword ptr 8
.text: 004012A2 arg_4 = dword ptr 0Ch
.text: 004012A2
.text: 004012A2 push ebp
.text: 004012A3 mov ebp , esp
.text: 004012A5 mov esi , [ebp +arg_0]
.text: 004012A8 add esi , 8
.text: 004012AB mov eax , [ebp +arg_4]
.text: 004012AE mov ecx , 10h
.text: 004012B3 xor ebx , ebx
.text: 004012B5
.text: 004012B5 loc_4012B5:
.text: 004012B5 xor edx , edx
.text: 004012B7 div ecx
.text: 004012B9 dec esi
.text: 004012BA add dl , 30h
.text: 004012BD cmp dl , 3Ah
.text: 004012C0 jb short loc_4012C5
.text: 004012C2 add dl , 7
.text: 004012C5
.text: 004012C5 loc_4012C5:
.text: 004012C5 mov [esi ], dl
.text: 004012C7 inc ebx
.text: 004012C8 cmp ebx , 8
.text: 004012CB jnz short loc_4012B5
.text: 004012CD leave
.text: 004012CE retn 8
.text: 004012CE sub_4012A2 endp
.text: 004012CE
}
.text: 004011A6 push dword_40321C
.text: 004011AC push offset unk_403224
.text: 004011B1 call sub_4012A2
.text: 004011B6 mov eax , offset unk_403224
.text: 004011BB add eax , 8
.text: 004011BE push dword_403220
.text: 004011C4 lea eax , [eax ]
.text: 004011C6 push eax
.text: 004011C7 call sub_4012A2
.text: 004011CC mov eax , offset unk_403224
.text: 004011D1 add eax , 10h
.text: 004011D4 push dword_403218
.text: 004011DA lea eax , [eax ]
.text: 004011DC push eax
.text: 004011DD call sub_4012A2
.text: 004011E2 mov eax , dword_403210
在这里反复的调用sub_4012A2函数,只要稍微用OD跟一下,我想即使不懂汇编也能明白,它这是在把我们在上面三个函数中得到的值连接起来!
下面的代码就很明显了,获取我们输入的注册码!.text: 004011E7 push eax
.text: 004011E8 call GetWindowTextLengthA
.text: 004011ED mov ecx , 0
.text: 004011F2 cmp eax , 18h
.text: 004011F5 jnz loc_40111B
.text: 004011FB inc eax
.text: 004011FC push eax
.text: 004011FD push offset String
.text: 00401202 push 3EAh
.text: 00401207 push [ebp +hDlg]
.text: 0040120A call GetDlgItemTextA
.text: 0040120F mov eax , offset String
.text: 00401214 call sub_4012EB
真正出现注册码的CALL 在这里sub_4012EB:
{
.text: 004012EB
.text: 004012EB
.text: 004012EB
.text: 004012EB
.text: 004012EB sub_4012EB proc near
.text: 004012EB mov edx , offset unk_SN
.text: 004012F0 add edx , 4
.text: 004012F3 mov byte ptr [edx ], 2Dh
.text: 004012F6 add edx , 0Ah
.text: 004012F9 mov byte ptr [edx ], 2Dh
.text: 004012FC mov edx , offset unk_SN
.text: 00401301 mov byte ptr [edx ], 4Bh
.text: 00401304 inc edx
.text: 00401305 mov byte ptr [edx ], 4Fh
.text: 00401308 inc edx
.text: 00401309 mov byte ptr [edx ], 53h
.text: 0040130C retn
.text: 0040130C sub_4012EB endp
}
好了,知道了这个,下面就剩下写注册机了~
怎么给程序打补丁我就不说了,如果大家有不知道的可以看我的源程序!
这里我只列出我的KEYGEN的算法部分!(程序本来就是用MASM32写的,所以我也就不翻译成C了,直接用内联汇编来写了,代码直接用IDA考出来时候,省时省力,嘿嘿~!)DWORD CKeygenDlg::CLName(char *Name)
{
DWORD result
int len = strlen(Name)
_asm{
mov eax ,Name
mov ebx ,len
xor edx ,edx
xor ecx ,ecx
L000:
mov dl , byte ptr [eax ]
imul ecx , ecx , 0x48
sub ecx , edx
sub ecx , 0x6F
mov edx , ecx
xor ecx , 0x0BACAF
inc eax
dec ebx
cmp ebx , 0
jnz L000
mov result,ecx
}
return result
}
DWORD CKeygenDlg::CkSn1(DWORD code)
{
DWORD result
_asm{
xor eax , eax
xor ebx , ebx
mov eax , code
mov ebx , code
mov edx , eax
xor edx , ebx
xor edx , 0x0FFAC
xor ebx , 0x553
add eax , ebx
add ebx , edx
dec ebx
add eax , ebx
mov result,eax
}
return result
}
DWORD CKeygenDlg::CkSn2(DWORD code)
{
DWORD result
_asm{
mov eax , code
mov ebx , code
xor ebx , 0x8E
add ebx , eax
mov result, ebx
}
return result
}
void CKeygenDlg::CkSn3(char *_addr,DWORD _code)
{
itoa(_code,_addr,16 )
}
char * CKeygenDlg::GetSerial(DWORD _addr)
{
char *Serial = NULL
_asm{
mov edx , _addr
add edx , 4
mov byte ptr [edx ], 0x2D
add edx , 0x0A
mov byte ptr [edx ], 0x2D
mov edx , _addr
mov byte ptr [edx ], 0x4B
inc edx
mov byte ptr [edx ], 0x4F
inc edx
mov byte ptr [edx ], 0x53
}
Serial = (char *)_addr
return Serial
}
void CKeygenDlg::OnKey()
{
//查找CM的窗口,确定程序是否已经启动!
……(省略,详见附件)
//先PATCH掉它对输入字符的个数限制
……(省略,详见附件)
//再PATCH掉它提示后就退出
……(省略,详见附件)
//再写一下它的算法了
const int nBufSize = 128
TCHAR chBuf[nBufSize]
ZeroMemory(chBuf,nBufSize)
DWORD t_rst
DWORD dwRet = nBufSize
if (::GetUserName(chBuf,&dwRet))
{
DWORD tmpsn = 0
char *tmpserial = new char[24 ]
m_Name = chBuf
tmpsn = CLName(chBuf)
CkSn3(tmpserial,tmpsn)
tmpserial += 8
t_rst = CkSn1(tmpsn)
CkSn3(tmpserial,t_rst)
tmpserial += 8
t_rst = CkSn2(tmpsn)
CkSn3(tmpserial,t_rst)
tmpserial -= 16
m_Serial = GetSerial((DWORD )tmpserial)
}
m_Serial. MakeUpper()
UpdateData(FALSE)
}
哈哈,第一次用IDA分析程序,真的很别扭,但是,不得不承认IDA功能的强大!
这个程序我从分析到写KEYGEN,一共用了将近4个小时,希望这个能对大家有所帮助!
[ 本帖最后由 bester 于 2009-2-13 02:18 编辑 ]