首页
社区
课程
招聘
[原创]一个简单的crackme分析 -- bb_cme1
发表于: 2015-5-17 23:35 8872

[原创]一个简单的crackme分析 -- bb_cme1

2015-5-17 23:35
8872

    适合新手,大大们飘过:D
    crackme链接:http://crackmes.de/users/svan70/bb_crackme1/
    通过查看可知该crackme为vc6.0所写,无壳。界面为一个序列号输入框和三个按钮,随意输入序列号后单击Check Code无反应,可以猜测只有输入正确时才有提示框,crackme界面如下:

    分析的突破点将采用字符串查找,用IDA载入程序,接着转到字符窗口,很容易就找到了Congratulations字符,双击字符串将会来到该变量定义的地方:aCongratulation db 'Congratulations!',0,在变量名aCongratulation上按下‘x’,将显示引用该变量的所有位置,只有一条引用,双击这条引用。这样就来到了.text:00401315处,下面将以这个地方作为突破口开始分析。
    首先,来到这个子函数的开头,可以看到程序分别根据arg_4参数和arg_8参数进行相应的跳转,连着这么多跳转很自然会让人想到switch case结构。顺便提一下,因为该子函数对于arg和loc变量的索引不是根据ebp来的,而是直接通过esp的偏移算出来的,所以通过IDA查看各个变量会更舒服些。通过分析可知00401044、00401047、0040104E这三处跳转分别对应Check Code、Exit和About这三个按钮的操作,这其中要关心的当然是Check Code处的跳转。

.text:00401020 8B 44 24 08                             mov     eax, [esp+arg_4]
.text:00401024 81 EC 1C 01 00 00                       sub     esp, 11Ch
.text:0040102A 2D 10 01 00 00                          sub     eax, 110h
.text:0040102F 55                                      push    ebp
.text:00401030 56                                      push    esi
.text:00401031 57                                      push    edi
.text:00401032 74 44                                   jz      short loc_401078
.text:00401034 48                                      dec     eax
.text:00401035 75 19                                   jnz     short loc_401050
.text:00401037 8B 84 24 34 01 00 00                    mov     eax, [esp+128h+arg_8]
.text:0040103E 25 FF FF 00 00                          and     eax, 0FFFFh
.text:00401043 48                                      dec     eax
.text:00401044 74 64                                   jz      short loc_4010AA
.text:00401046 48                                      dec     eax
.text:00401047 74 40                                   jz      short loc_401089
.text:00401049 2D E7 03 00 00                          sub     eax, 3E7h
.text:0040104E 74 0E                                   jz      short loc_40105E

    双击loc_4010AA后,便来到Check Code按钮所处理的代码处。lea指令是取局部变量地址用的,offset也是取址用的,不过它取的是全局变量的地址。[esp+128h+buffer]表示一个局部变量,esp+128h+buffer表示这个局部变量的地址,因此edx=esp+128h+buffer,这里的buffer是自定义的名称,可以在想更改的名称上按‘n’进行重命名。程序接着调用SendDlgItemMessageA函数,局部变量buffer处将保存输入框中的序列号,注意一下局部变量var_10C、var_108、var_104处写入的三个值,后面会用到。

.text:004010AA 8B BC 24 2C 01 00 00                    mov     edi, [esp+128h+hWnd]
.text:004010B1 8D 54 24 28                             lea     edx, [esp+128h+buffer]
.text:004010B5 52                                      push    edx             ; lParam
.text:004010B6 68 00 01 00 00                          push    100h            ; wParam
.text:004010BB 6A 0D                                   push    0Dh             ; Msg
.text:004010BD 68 E8 03 00 00                          push    3E8h            ; nIDDlgItem
.text:004010C2 57                                      push    edi             ; hDlg
.text:004010C3 C7 44 24 30 E4 38 28 07                 mov     [esp+13Ch+var_10C], 72838E4h
.text:004010CB C7 44 24 34 D4 B9 C2 6D                 mov     [esp+13Ch+var_108], 6DC2B9D4h
.text:004010D3 C7 44 24 38 1E ED E1 3A                 mov     [esp+13Ch+var_104], 3AE1ED1Eh
.text:004010DB FF 15 A4 50 40 00                       call    ds:SendDlgItemMessageA
.text:004010E1 85 C0                                   test    eax, eax
.text:004010E3 74 93                                   jz      short loc_401078

    再往后看,发现程序接下来的代码量还蛮多的,至少看起来有很多行,一个办法就是用OD跟一下这段代码,书读百遍其义自现,程序跟多了自然也会有感觉。在004010DB处的SendDlgItemMessageA调用下个断点,F9跑起来,随便输入一串序列号,单击Check Code程序就断下来了。因为Congratulations字符在这个子函数的末尾,也就是说接下来的代码一直要执行到末尾才有机会去运行Congratulations处的代码,这之间如果有retn返回,那么就肯定出错了。目标很明确了,F8单步往下跟,由于序列号是随意输入的,要是正确那才奇怪,所以当碰到jnz这些条件转移指令时,若发现按当前的跳转执行下去就出错返回了,那么可以直接在寄存器区域修改ZF标志位,改变程序的执行流程,当然这样修改后程序很可能会跟奔掉。多跟几遍就会发现接下来的程序可以分成三段,每一段几乎是一样的,然后就到Congratulations处的代码了。下面将分析这三段中最开始的那段,也就是004010E5到0040119A之间的代码,其它两段是相似的。

由IDA可知[0x406330]变量(IDA中为dword_406330)是恒为1的,后面将多次用到该变量,因此004010F1往下的几条指令可以不用看了,直接到00401109处。
004010E5     A1 30634000   MOV EAX,DWORD PTR DS:[0x406330]
004010EA     BD 01000000   MOV EBP,0x1
004010EF     3BC5          CMP EAX,EBP
004010F1     7E 16         JLE SHORT bb_cme1.00401109
004010F3     8B4424 28     MOV EAX,DWORD PTR SS:[ESP+0x28]
004010F7     6A 04         PUSH 0x4
004010F9     25 FF000000   AND EAX,0xFF
004010FE     50            PUSH EAX
004010FF     E8 9E050000   CALL bb_cme1.004016A2
00401104     83C4 08       ADD ESP,0x8
00401107     EB 16         JMP SHORT bb_cme1.0040111F

结合着IDA,ESP+0x28实际上就是输入序列号的栈起始地址,也可以从OD的堆栈中看出来,接着edx将会被赋值为0040612E,通过随后的分析可知以0040612E为起始地址的数据段可以看成一张数表,指令00401119其实就是一个查表操作,每次查表的偏移对应输入序列号中单个字符的ASCII码值乘2,因此只要关心以0040612E为起始地址的256个字节数据。
00401109     8B4C24 28     MOV ECX,DWORD PTR SS:[ESP+0x28]
0040110D     8B15 24614000 MOV EDX,DWORD PTR DS:[0x406124]          ;  bb_cme1.0040612E
00401113     81E1 FF000000 AND ECX,0xFF
00401119     8A044A        MOV AL,BYTE PTR DS:[EDX+ECX*2]
0040111C     83E0 04       AND EAX,0x4
0040111F     85C0          TEST EAX,EAX
00401121     75 0E         JNZ SHORT bb_cme1.00401131
00401123     5F            POP EDI
00401124     8BC5          MOV EAX,EBP
00401126     5E            POP ESI
00401127     5D            POP EBP
00401128     81C4 1C010000 ADD ESP,0x11C
0040112E     C2 1000       RETN 0x10
这个表后面将多次用到,通过IDA可以查看这256个字节。接着看0040111C处开始的指令,要想在jnz跳转时不走到retn,al和0x4相与的结果必须为1。结合下面的表,因此指令00401119处查表后得到的结果必须为0x84,因此查表的偏移必须为0x30到0x39。对于ASCII码值为0x30~0x39是不是有点熟悉,也就是字符1~9,所以输入的序列号必须以数字开始,接着将跳转到00401131处。
0040612E  20 00 20 00 20 00 20 00  20 00 20 00 20 00 20 00
0040613E  20 00 28 00 28 00 28 00  28 00 28 00 20 00 20 00
0040614E  20 00 20 00 20 00 20 00  20 00 20 00 20 00 20 00
0040615E  20 00 20 00 20 00 20 00  20 00 20 00 20 00 20 00
0040616E  48 00 10 00 10 00 10 00  10 00 10 00 10 00 10 00
0040617E  10 00 10 00 10 00 10 00  10 00 10 00 10 00 10 00
0040618E  84 00 84 00 84 00 84 00  84 00 84 00 84 00 84 00
0040619E  84 00 84 00 10 00 10 00  10 00 10 00 10 00 10 00
004061AE  10 00 81 00 81 00 81 00  81 00 81 00 81 00 01 00
004061BE  01 00 01 00 01 00 01 00  01 00 01 00 01 00 01 00
004061CE  01 00 01 00 01 00 01 00  01 00 01 00 01 00 01 00
004061DE  01 00 01 00 01 00 10 00  10 00 10 00 10 00 10 00
004061EE  10 00 82 00 82 00 82 00  82 00 82 00 82 00 02 00
004061FE  02 00 02 00 02 00 02 00  02 00 02 00 02 00 02 00
0040620E  02 00 02 00 02 00 02 00  02 00 02 00 02 00 02 00
0040621E  02 00 02 00 02 00 10 00  10 00 10 00 10 00 20 00

继续分析,接下来的代码和刚刚分析过的还蛮像的,毫无疑问00401139处的跳转将来到0040114E处,还是和之前一样的查表操作,不过因为有了esi这个偏移,序列号中的字符将逐个往下分析,如果是数字则跳到00401133处循环执行。最终肯定是要跳出循环的,跳出循环后将来到00401167处,此时导致循环跳出的字符将和0x2D比较,如果不等就出错返回了,因此导致循环跳出的字符ASCII码值为0x2D,也就是字符‘-’,这和查表结果也是相符的。
00401131     8BF5          MOV ESI,EBP
00401133     392D 30634000 CMP DWORD PTR DS:[0x406330],EBP
00401139     7E 13         JLE SHORT bb_cme1.0040114E
0040113B     33C0          XOR EAX,EAX
0040113D     6A 04         PUSH 0x4
0040113F     8A4434 2C     MOV AL,BYTE PTR SS:[ESP+ESI+0x2C]
00401143     50            PUSH EAX
00401144     E8 59050000   CALL bb_cme1.004016A2
00401149     83C4 08       ADD ESP,0x8
0040114C     EB 12         JMP SHORT bb_cme1.00401160
0040114E     8B15 24614000 MOV EDX,DWORD PTR DS:[0x406124]          ;  bb_cme1.0040612E
00401154     33C9          XOR ECX,ECX
00401156     8A4C34 28     MOV CL,BYTE PTR SS:[ESP+ESI+0x28]
0040115A     8A044A        MOV AL,BYTE PTR DS:[EDX+ECX*2]
0040115D     83E0 04       AND EAX,0x4
00401160     85C0          TEST EAX,EAX
00401162     74 03         JE SHORT bb_cme1.00401167
00401164     46            INC ESI
00401165     EB CC         JMP SHORT bb_cme1.00401133
00401167     807C34 28 2D  CMP BYTE PTR SS:[ESP+ESI+0x28],0x2D
0040116C     0F85 B4010000 JNZ bb_cme1.00401326

接下来将是三个call调用了,分别是CALL bb_cme1.00401606、CALL bb_cme1.004015EF和CALL bb_cme1.00401340,暂时先不去关心这三处call调用。不过注意一下0040119A处的指令,call调用后的返回参数eax将存到一个局部变量中。
00401172     8D4424 28     LEA EAX,DWORD PTR SS:[ESP+0x28]
00401176     68 88604000   PUSH bb_cme1.00406088
0040117B     50            PUSH EAX
0040117C     46            INC ESI
0040117D     E8 84040000   CALL bb_cme1.00401606

00401182     8D4C24 14     LEA ECX,DWORD PTR SS:[ESP+0x14]
00401186     6A 0A         PUSH 0xA
00401188     51            PUSH ECX
00401189     50            PUSH EAX
0040118A     E8 60040000   CALL bb_cme1.004015EF

0040118F     68 71A3CEF2   PUSH 0xF2CEA371                          ; Arg2 = F2CEA371
00401194     50            PUSH EAX                                 ; Arg1 = 3BB2A8F6
00401195     E8 A6010000   CALL bb_cme1.00401340                    ; bb_cme1.00401340
0040119A     894424 2C     MOV DWORD PTR SS:[ESP+0x2C],EAX

    至此,第一段004010E5到0040119A之间的代码就过一遍了,因为接下来的两段代码和第一段几乎是一样的,因此可以判断序列号是分为三段的,每一段将是一串数字字符并以‘-’字符结束。当然,对第三段代码的分析可知第三段数字字符串并不是以‘-’结束的,而直接是字符串结束标志,因此得到序列号的格式应该是形如xxxx-xxxx-xxxx的字符串,x表示数字,至于x的个数仍然是未知的。最后,终于来到了子函数末尾的Congratulations代码处。

    这段代码就是依次比较以局部变量var_118和var_10C为起始的连续0Ch个字节,如果这0Ch个字节都相等,那么将出现Congratulations提示窗,否则出错返回。还记得最开始SendDlgItemMessageA处有三个局部变量的赋值操作吗?没错,就是在这里用到了,而且也应该记得处理完每一段序列号的最后都有一个局部变量赋值操作。现在应该清楚了,xxxx-xxxx-xxxx这三段序列号每一段处理完后程序的期望返回值分别对应SendDlgItemMessageA下面的72838E4h、6DC2B9D4h和3AE1ED1Eh。当然,可以简单的将0040130B处的指令用nop填充,这样随意输入形如xxxx-xxxx-xxxx的序列号都会跳出Congratulations提示,但该crackme要求不能通过打补丁的方法破解,必须找到正确的序列号。因此,要接着分析前面暂时没关心的那三处call调用。
.text:004012FF 33 C0                                   xor     eax, eax
.text:00401301
.text:00401301                         loc_401301:                             
.text:00401301 8A 54 04 10                             mov     dl, byte ptr [esp+eax+128h+var_118]
.text:00401305 8A 4C 04 1C                             mov     cl, byte ptr [esp+eax+128h+var_10C]
.text:00401309 32 D1                                   xor     dl, cl
.text:0040130B 75 19                                   jnz     short loc_401326
.text:0040130D 40                                      inc     eax
.text:0040130E 83 F8 0C                                cmp     eax, 0Ch
.text:00401311 7C EE                                   jl      short loc_401301
.text:00401313 6A 00                                   push    0               ; uType
.text:00401315 68 74 60 40 00                          push    offset aCongratulation ; "Congratulations!"
.text:0040131A 68 30 60 40 00                          push    offset aYourCodeIsCorr ; "Your code is correct!\nPlease send your"...
.text:0040131F 57                                      push    edi             ; hWnd
.text:00401320 FF 15 9C 50 40 00                       call    ds:MessageBoxA

    首先来到第一处CALL bb_cme1.00401606,F7跟进去。程序看起来有很多行,不过执行的操作却很简单。程序先对‘-’字符生成一个标记操作,当序列号xxxx-xxxx-xxxx执行同样的一套流程后,会在‘-’处跳出来,这时程序将‘-’地址处置零,这样序列号就以‘-’分割开了,于是eax返回的是字符串xxxx的首地址,而剩下的字符串xxxx-xxxx的首地址将保留在[0x4085B4]里。
这里有一个地方要说明,如下,执行完前四条指令后,eax为0、ecx为8、edi为loc8处的起始地址,当执行第五条指令后以edi为起始地址的8个4字节将全部被置零。
00401612    6A 08         PUSH 0x8
00401614    33C0          XOR EAX,EAX
00401616    59            POP ECX
00401617    8D7D E0       LEA EDI,[LOCAL.8]
0040161A    F3:AB         REP STOS DWORD PTR ES:[EDI]

    接着再看第二处CALL bb_cme1.004015EF,F7跟进去,又是一处call调用,F7再跟进去,发现这个子函数还是蛮复杂的,老办法,用OD跟着跑几遍。可以注意到CALL bb_cme1.00401340将会用到这个子函数的返回参数eax,而eax最终又是由子函数中的loc2对其赋值,跟了几遍后逆着往前推,就注意到如下这个地方:
00401542    0FAF75 10     IMUL ESI,[ARG.3]
00401546    03F1          ADD ESI,ECX
00401548    8975 F8       MOV [LOCAL.2],ESI
0040154B    8B45 FC       MOV EAX,[LOCAL.1]
0040154E    FF45 FC       INC [LOCAL.1]
00401551    8A18          MOV BL,BYTE PTR DS:[EAX]
00401553    E9 64FFFFFF   JMP bb_cme1.004014BC
其中arg.3是定值0xa,也就是10,ecx为序列号中的字符ASCII码值减0x30后的值,粗略分析后不难发现返回值eax就是入参字符串xxxx对应的整数值。

    是时候来看一下CALL bb_cme1.00401340处的内容了,这个调用是很关键的,该子函数有两个参数,其中arg.1为CALL bb_cme1.004015EF的返回参数,另一参数arg.2则为定值0xF2CEA371。由于该调用期望的正确返回结果是已知的,可判断arg.1是小于arg.2的,因此程序给eax和ebx初始化后,将重复执行mul eax、div ebx、mov eax,edx这三条指令。对于mul eax,程序将执行eax*eax,并将结果存于edx:eax中,接着div ebx,程序将执行edx:eax/ebx,并将商存于eax中,余数存于edx中,最后执行mov指令,其实,这三条指令就相当于eax=eax*eax mod ebx。
00401340    55            PUSH EBP
00401341    8BEC          MOV EBP,ESP
00401343    8B45 08       MOV EAX,[ARG.1]
00401346    8B55 0C       MOV EDX,[ARG.2]
00401349    3BC2          CMP EAX,EDX
0040134B    73 74         JNB SHORT bb_cme1.004013C1
0040134D    53            PUSH EBX
0040134E    8B45 08       MOV EAX,[ARG.1]
00401351    8B5D 0C       MOV EBX,[ARG.2]
00401354    F7E0          MUL EAX
00401356    F7F3          DIV EBX
00401358    8BC2          MOV EAX,EDX
……
此处重复MUL EAX、DIV EBX、MOV EAX,EDX
……
004013B4    8B5D 08       MOV EBX,[ARG.1]
004013B7    F7E3          MUL EBX
004013B9    8B5D 0C       MOV EBX,[ARG.2]
004013BC    F7F3          DIV EBX
004013BE    8BC2          MOV EAX,EDX
004013C0    5B            POP EBX
004013C1    5D            POP EBP
004013C2    C3            RETN

因此,上述子函数的伪代码就等价于:
a=arg.1,b=arg.2;
c=a;
for(i=0; i<16; ++i){
    c=(c*c)%b;
}
c=(c*a)%b;

    其中,程序最终的期望值c是已知的,目标就是使得到的c值正确。如果真如之前对CALL bb_cme1.004015EF所粗略分析的那样,bb_cme1.004015EF调用将形如xxxx-xxxx-xxxx序列号中的每一段xxxx转成整数,即类似atoi函数,那么要是能逆推出a的话,这三段序列号自然也就得到了,将整数a转成字符串看一眼就应该出来了:D。现在将精力放在这短短的几行伪代码上,已知条件就a未知,好像用穷举法可以搞定,但不切实际。记得这个crackme有一个hint:Little crypto knowledge is advantage,也就是如果了解加解密的话,这将很有优势。常见的加密算法有DES、AES、RSA等,而这段子函数的主要操作是平方取模,很自然的会联想到RSA里的幂模运算。关于幂模运算举一个简单的例子,假设计算3^9 mod 5,可分解为如下计算:

3^1=(3^0)^2*3 mod 5=3 mod 5=3
3^2=((3^0)^2*3))^2 mod 5=3^2 mod 5=4
3^4=(((3^0)^2*3))^2)^2 mod 5=4^2 mod 5=1
3^9=((((3^0)^2*3))^2)^2)^2*3 mod 5=1^2*3 mod 5=3

    这样分解后每一步的运算就相对简单了,不会遇到特别大的数值,原理也还是较好理解的。为了后面的分析,还是有必要简单提一下RSA。RSA算法涉及三个参数,n、e1、e2。其中,n是两个大质数p、q的积,e1和e2是一对相关的值,e1可以任意取,但要求e1与(p-1)*(q-1)互质,再选择e2,要求(e2*e1)mod((p-1)*(q-1))=1。(n,e1),(n,e2)就是密钥对。设A为明文,B为密文,则:A=B^e2 mod n;B=A^e1 mod n,e1和e2可以互换使用。因为e1、e2可能会比较大,直接进行幂模运算会遇到特别大的值,因此会用到上面提到的分解方法。

    再来看该子函数,由前面的分析可知形如xxxx-xxxx-xxxx的序列号将以‘-’分为三段,每一段字符串转化为整数,成为该子函数的arg.1参数,经过加密后(现在可以这么猜测了)这三段的密文分别为0x72838E4, 0x6DC2B9D4, 0x3AE1ED1E。对应到公式B=A^e1 mod n,B、e1和n都已知了,比如序列号的第一段,密文B=0x72838E4,n毫无疑问就是arg.2了,也就是n=0xF2CEA371=4073628529,而该子函数中用了16次平方取模后又乘了一次明文,因此e1=2^16+1=65537。如果之前的猜测都正确的话,那么n=4073628529应该为两个质数的乘积,通过简单的求约数方法,n对2到sqrt(n)之间的数取模得到约数47051,而4073628529=47051*86579,经过验证47051和86579确实都是质数,看来很有希望了。这样p=47051,q=86579,通过辗转相除法,可以验证e1确实与(p-1)*(q-1)互质,再通过公式(e2*e1)mod((p-1)*(q-1))=1算出e2=3057436473,这里一定要写个小程序去算,看是看不出来的,记得数据类型要为unsigned long long,如果是unsigned int数值会溢出的。最后,通过公式A=B^e2 mod n就可以算出A了,也就是arg.1的值,而通过arg.1的值显然就可以得到猜测的序列号了,代码如下:

#include <stdio.h>
#include <stdlib.h>

int main()
{
  unsigned int encrypt[]={0x72838E4, 0x6DC2B9D4, 0x3AE1ED1E}, decrypt[3];
  unsigned int n=4073628529, m=3057436473, flag;
  unsigned long long x;
  int i, j;

  for(i=0; i<3; ++i)
  {
    x=1;
    flag=0x80000000;
    for(j=0; j<32; ++j)
    {
      x=(x*x)%n;
      if((m&flag)>>(31-j) == 1){
        x=(x*encrypt[i])%n;
      }
      flag=flag>>1;
    }
    decrypt[i]=x;
  }
  printf("key: %u-%u-%u\n", decrypt[0], decrypt[1], decrypt[2]);
  system("pause");

  return 0;
}

    程序的输出结果为key: 580276954-895936478-64598366
    如果分析都正确的话,那么输入这个key就会有Congratulations了:D



bb_cme1.zip


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 3
支持
分享
最新回复 (6)
雪    币: 39
活跃值: (158)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
问一个你开始分析的问题,你是怎么知道输入正确后显示Congratulations字符串的?是你碰巧输入正确了弹框你看到了?还是你是作者?  随便问问,没别的意思,新手喜欢刨根问底。
2015-5-18 10:18
0
雪    币: 4230
活跃值: (1435)
能力值: (RANK:270 )
在线值:
发帖
回帖
粉丝
3
同新手,我的一点理解,crackme的作者让别人去破解他的程序,最后肯定要告诉人家破解的对不对,所以多少都会有些提示性的话,就好比这个程序,当你看到如下提示时:
.text:00401313 6A 00                                   push    0               ; uType
.text:00401315 68 74 60 40 00                          push    offset aCongratulation ; "Congratulations!"
.text:0040131A 68 30 60 40 00                          push    offset aYourCodeIsCorr ; "Your code is correct!\nPlease send your"...
.text:0040131F 57                                      push    edi             ; hWnd
.text:00401320 FF 15 9C 50 40 00                       call    ds:MessageBoxA
你就能确定结果对了,不是说一定要是Congratulations,也可以是其它提示符,应根据具体程序查找到的字符串来判断,只不过对于这个程序而言,Congratulations扮演着这样的角色。
2015-5-18 18:15
0
雪    币: 39
活跃值: (158)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
要是把Congratulations换成ko,就有得你找了(出于交流的语气)?
2015-5-19 09:21
0
雪    币: 4230
活跃值: (1435)
能力值: (RANK:270 )
在线值:
发帖
回帖
粉丝
5
寻找crackme的突破点有几种常见方法,字符串查找只是其中的一种,还有API断点、F12暂停等方法,哪个方便就用哪个,可以看看CCDebuger大神写的经典教程:
http://bbs.pediy.com/showthread.php?t=21308
http://bbs.pediy.com/showthread.php?t=21330
http://bbs.pediy.com/showthread.php?t=21532
当然,就该crackme来说,我觉得作者把重点放在后面的RSA加密上了,所以简单的字符查找方法就得到了分析点。
2015-5-19 21:40
0
雪    币: 6534
活跃值: (3666)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
楼主写得不错, 把后面解密写得比较详细..
2015-9-19 12:19
0
雪    币: 49
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
瓦特则法克?
2015-10-20 09:55
0
游客
登录 | 注册 方可回帖
返回
//