大概从这开始记录吧。。之前的wp清系统之前没有存GG了
首先打开程序看看界面
可以看到有弹框提示字符。。
IDA也可以轻松找到DialogFunc
但这题在按钮事件加了无数花。。大概看了一下就懒得看了
于是想到GetDlgItemText下断然后下访问断点的方式去找算法位置
最后找到是在RVA00001450的地方是算法函数的地址
对算法开始分析:
03301497 56 push esi ; 计算流程开始
03301498 8BF7 mov esi,edi
0330149A 8D4E 01 lea ecx,dword ptr ds:[esi+0x1]
0330149D 8D49 00 lea ecx,dword ptr ds:[ecx]
033014A0 8A06 mov al,byte ptr ds:[esi]
033014A2 46 inc esi
033014A3 84C0 test al,al
033014A5 ^ 75 F9 jnz short 033014A0
033014A7 2BF1 sub esi,ecx ; 计算Serial长度,存esi
033014A9 8D46 ED lea eax,dword ptr ds:[esi-0x13] ; 长度-0x13h后送eax
033014AC 83F8 31 cmp eax,0x31 ; 比较eax和0x31h的大小,即长度和0x31h+0x13h=0x44h
033014AF 0F87 AD040000 ja 03301962 ; 实现了Serial长度在0x13h和0x44h之间的限制
上面这段实现了对Serial长度的限制,这里的限制是不能少于18位,不能多于68位,那么自然就有猜测是否分成两部分(18+?)进行验证,后面的分析也会证实这点。
首先的发现是对Name的处理:
在1200h的函数里面
03301200 55 push ebp
03301201 8BEC mov ebp,esp
03301203 83EC 0C sub esp,0xC
03301206 53 push ebx
03301207 8BD9 mov ebx,ecx
03301209 8BD3 mov edx,ebx
0330120B 895D FC mov dword ptr ss:[ebp-0x4],ebx
0330120E 56 push esi
0330120F 33F6 xor esi,esi
03301211 57 push edi
03301212 33FF xor edi,edi
03301214 8975 F8 mov dword ptr ss:[ebp-0x8],esi
03301217 8D4A 01 lea ecx,dword ptr ds:[edx+0x1]
0330121A 8D9B 00000000 lea ebx,dword ptr ds:[ebx]
03301220 8A02 mov al,byte ptr ds:[edx] ; 取一个字符
03301222 42 inc edx ; edx自增
03301223 84C0 test al,al
03301225 ^ 75 F9 jnz short 03301220
03301227 2BD1 sub edx,ecx ; 取Name长度
03301229 33C9 xor ecx,ecx
0330122B 8955 F4 mov dword ptr ss:[ebp-0xC],edx ; 长度存栈
0330122E 83FA 02 cmp edx,0x2
03301231 72 27 jb short 0330125A ; 长度小于2跳
03301233 8D5A FF lea ebx,dword ptr ds:[edx-0x1] ; ebx = edx - 0x1
03301236 8B55 FC mov edx,dword ptr ss:[ebp-0x4] ; edx取字串
03301239 8DA424 00000000 lea esp,dword ptr ss:[esp]
03301240 0FBE040A movsx eax,byte ptr ds:[edx+ecx] ; eax取字符
03301244 03F0 add esi,eax ; 累加到esi
03301246 0FBE440A 01 movsx eax,byte ptr ds:[edx+ecx+0x1] ; eax再取字符
0330124B 83C1 02 add ecx,0x2 ; ecx计数器自增2
0330124E 03F8 add edi,eax ; 第二个字符累加到edi
03301250 3BCB cmp ecx,ebx
03301252 ^ 72 EC jb short 03301240 ; 若有两个及以上字符则回跳继续处理
03301254 8B55 F4 mov edx,dword ptr ss:[ebp-0xC]
03301257 8B5D FC mov ebx,dword ptr ss:[ebp-0x4]
0330125A 3BCA cmp ecx,edx
0330125C 73 07 jnb short 03301265 ; 判断是否仍有字符
0330125E 0FBE0419 movsx eax,byte ptr ds:[ecx+ebx]
03301262 8945 F8 mov dword ptr ss:[ebp-0x8],eax
03301265 8D0437 lea eax,dword ptr ds:[edi+esi]
03301268 0345 F8 add eax,dword ptr ss:[ebp-0x8] ; 全部和加起来送eax
0330126B 5F pop edi ; 0019F728
0330126C 5E pop esi ; 0019F728
0330126D 5B pop ebx ; 0019F728
0330126E 8BE5 mov esp,ebp
03301270 5D pop ebp ; 0019F728
03301271 C3 retn
这个函数简单的进行了一个ASCII累加的处理
之后取了这个累加和的奇偶作为后续算法的一部分
然后就是对Serial前18位的处理了
这18位被分成了2 * 3 * 3这样的形式处理
每两位生成一个数,参考官方给的Name为360的Serial的前18位:
323031303330213032
每两个为一组,然后3 * 3组,于是:
32 30 31
30 33 30
21 30 32
联想到ascii码的我。。
问题在于这里有个21,那么看看汇编吧
汇编里对应处理的部分如下:
033014FE E8 FDFCFFFF call 03301200
03301503 83E0 01 and eax,0x1 ; 判断奇偶用,奇数结果为1,偶数为0
03301506 C785 58FFFFFF 03>mov dword ptr ss:[ebp-0xA8],0x3
03301510 8D8D 58FFFFFF lea ecx,dword ptr ss:[ebp-0xA8]
03301516 8985 3CFFFFFF mov dword ptr ss:[ebp-0xC4],eax ; 奇偶结果存在ebp-0xC4
0330151C C785 5CFFFFFF 03>mov dword ptr ss:[ebp-0xA4],0x3
03301526 E8 D5FAFFFF call 03301000
0330152B 32C0 xor al,al ; 清空al
0330152D 8885 6BFFFFFF mov byte ptr ss:[ebp-0x95],al ; ebp-0x95清零
03301533 0FB6C0 movzx eax,al ; eax清零
03301536 32FF xor bh,bh
03301538 8985 64FFFFFF mov dword ptr ss:[ebp-0x9C],eax ; ebp-0x9C清零
0330153E 8D0440 lea eax,dword ptr ds:[eax+eax*2]
03301541 0FB6FF movzx edi,bh ; edi清零
03301544 83C9 FF or ecx,-0x1
03301547 8D3407 lea esi,dword ptr ds:[edi+eax] ; esi清零
0330154A 8A5475 E8 mov dl,byte ptr ss:[ebp+esi*2-0x18] ; dl取Serial一个字符
0330154E 8AC2 mov al,dl
03301550 2C 30 sub al,0x30
03301552 3C 09 cmp al,0x9 ; 判断是否是数字0~9
03301554 77 08 ja short 0330155E ; 不是跳走
03301556 0FBECA movsx ecx,dl
03301559 83E9 30 sub ecx,0x30
0330155C EB 1E jmp short 0330157C
0330155E 8AC2 mov al,dl ; 不是数字的话判断是否是字母A~F
03301560 2C 41 sub al,0x41
03301562 3C 05 cmp al,0x5
03301564 77 08 ja short 0330156E
03301566 0FBECA movsx ecx,dl
03301569 83E9 37 sub ecx,0x37
0330156C EB 0E jmp short 0330157C
0330156E 8AC2 mov al,dl ; 再不是的话就是小写的a~f
03301570 2C 61 sub al,0x61
03301572 3C 05 cmp al,0x5
03301574 77 06 ja short 0330157C
03301576 0FBECA movsx ecx,dl
03301579 83E9 57 sub ecx,0x57
0330157C 81E1 01000080 and ecx,0x80000001 ; 检查奇偶
03301582 79 05 jns short 03301589
03301584 49 dec ecx
03301585 83C9 FE or ecx,-0x2
03301588 41 inc ecx
03301589 8A5C75 E9 mov bl,byte ptr ss:[ebp+esi*2-0x17] ; 第二个字符
0330158D 83CA FF or edx,-0x1 ; 往下还是和刚刚一套判断
03301590 8AC3 mov al,bl
03301592 2C 30 sub al,0x30
03301594 3C 09 cmp al,0x9
03301596 77 08 ja short 033015A0
03301598 0FBED3 movsx edx,bl
0330159B 83EA 30 sub edx,0x30
0330159E EB 1E jmp short 033015BE
033015A0 8AC3 mov al,bl
033015A2 2C 41 sub al,0x41
033015A4 3C 05 cmp al,0x5
033015A6 77 08 ja short 033015B0
033015A8 0FBED3 movsx edx,bl
033015AB 83EA 37 sub edx,0x37
033015AE EB 0E jmp short 033015BE
033015B0 8AC3 mov al,bl
033015B2 2C 61 sub al,0x61
033015B4 3C 05 cmp al,0x5
033015B6 77 06 ja short 033015BE
033015B8 0FBED3 movsx edx,bl
033015BB 83EA 57 sub edx,0x57
033015BE 66:0F6ECA movd mm1,edx
033015C2 0f5bc9 cvtdq2ps xmm1,xmm1
033015C5 3B8D 3CFFFFFF cmp ecx,dword ptr ss:[ebp-0xC4] ; 当Serial奇数位数字奇偶与Name的ascii码之和奇偶不同时
033015CB 74 0A je short 033015D7 ; Serial偶数位数值取负值
033015CD 0F57C0 xorps xmm0,xmm0
033015D0 F3:0F5CC1 subss xmm0,xmm1
033015D4 0F28C8 movaps xmm1,xmm0
033015D7 8B8D 64FFFFFF mov ecx,dword ptr ss:[ebp-0x9C]
033015DD 3B8D 58FFFFFF cmp ecx,dword ptr ss:[ebp-0xA8] ; 循环结束条件
033015E3 0F8D 79030000 jge 03301962
033015E9 8B95 5CFFFFFF mov edx,dword ptr ss:[ebp-0xA4]
033015EF 3BFA cmp edi,edx ; 循环结束条件2
033015F1 0F8D 6B030000 jge 03301962
033015F7 8BC2 mov eax,edx
033015F9 FEC7 inc bh ; bh作计数器
033015FB 8B95 60FFFFFF mov edx,dword ptr ss:[ebp-0xA0]
03301601 0FAFC1 imul eax,ecx
03301604 03C7 add eax,edi
03301606 F3:0F110C82 movss dword ptr ds:[edx+eax*4],xmm1
0330160B 8D0449 lea eax,dword ptr ds:[ecx+ecx*2]
0330160E 80FF 03 cmp bh,0x3 ; 共3次 处理6个字符
03301611 ^ 0F82 2AFFFFFF jb 03301541 ; 回去处理下两个字符
03301617 8A85 6BFFFFFF mov al,byte ptr ss:[ebp-0x95]
0330161D 04 01 add al,0x1 ; al是又一个计数器
0330161F 8885 6BFFFFFF mov byte ptr ss:[ebp-0x95],al
03301625 3C 03 cmp al,0x3 ; 又是3次 于是一共是18个
03301627 ^ 0F82 06FFFFFF jb 03301533
可以看到其实也并不是ASCII码。。2个数的前一个是用来和前面运算过的Name的ASCII累加和的奇偶进行比较的,如果这两个奇偶不同,那么后面一个数就取负值。
另外值得一提的是cvtdq2ps是压缩有符号双字整数转换成压缩单精度浮点值的作用
于是我们可以看到算法从这18位生成了一个矩阵:
2 0 1
0 3 0
-1 0 2
那我们接下来关心的部分就是这个矩阵将会如何处理了
但是由于有很多xmm寄存器的调用。。于是我从od转了x32dbg,地址会有一定改变不要在意QAQ
接下来首先程序在内存中放了一些数
整理出来大概是两个3 * 3矩阵
1 0 1
0 2 0
-1 0 1
1 0 0
0 1 0
0 0 1
继续看汇编。。
接下来首先用了个循环把两个矩阵放到了其他地方
然后进行了矩阵乘法运算
下面是相关代码,从两个矩阵的取值方式很容易看出是矩阵乘法了
02A61141 | 33 F6 | xor esi,esi |
02A61143 | 85 DB | test ebx,ebx |
02A61145 | 0F 8E 93 00 00 00 | jle 2A611DE |
02A6114B | EB 03 | jmp 2A61150 |
02A6114D | 8D 49 00 | lea ecx,dword ptr ds:[ecx] |
02A61150 | 33 D2 | xor edx,edx |
02A61152 | 0F 57 DB | xorps xmm3,xmm3 |
02A61155 | 39 51 04 | cmp dword ptr ds:[ecx+4],edx |
02A61158 | 7E 5D | jle 2A611B7 |
02A6115A | 8B 5D FC | mov ebx,dword ptr ss:[ebp-4] |
02A6115D | 8B 45 08 | mov eax,dword ptr ss:[ebp+8] |
02A61160 | 3B 3B | cmp edi,dword ptr ds:[ebx] |
02A61162 | 7D 19 | jge 2A6117D |
02A61164 | 8B 4B 04 | mov ecx,dword ptr ds:[ebx+4] |
02A61167 | 3B D1 | cmp edx,ecx |
02A61169 | 7D 12 | jge 2A6117D |
02A6116B | 8B 43 08 | mov eax,dword ptr ds:[ebx+8] | eax:第一个矩阵地址
02A6116E | 0F AF CF | imul ecx,edi |
02A61171 | 03 CA | add ecx,edx |
02A61173 | F3 0F 10 04 88 | movss xmm0,dword ptr ds:[eax+ecx*4] | xmm0取第一个矩阵的数(按行)
02A61178 | 8B 45 08 | mov eax,dword ptr ss:[ebp+8] |
02A6117B | EB 03 | jmp 2A61180 |
02A6117D | 0F 28 C2 | movaps xmm0,xmm2 |
02A61180 | 3B 10 | cmp edx,dword ptr ds:[eax] |
02A61182 | 7D 16 | jge 2A6119A |
02A61184 | 8B 48 04 | mov ecx,dword ptr ds:[eax+4] |
02A61187 | 3B F1 | cmp esi,ecx |
02A61189 | 7D 0F | jge 2A6119A |
02A6118B | 8B 40 08 | mov eax,dword ptr ds:[eax+8] | eax:输入矩阵地址
02A6118E | 0F AF CA | imul ecx,edx |
02A61191 | 03 CE | add ecx,esi |
02A61193 | F3 0F 10 0C 88 | movss xmm1,dword ptr ds:[eax+ecx*4] | xmm1取输入矩阵的数(按列)
02A61198 | EB 03 | jmp 2A6119D |
02A6119A | 0F 28 CA | movaps xmm1,xmm2 |
02A6119D | 8B 45 08 | mov eax,dword ptr ss:[ebp+8] |
02A611A0 | 42 | inc edx | edx计数器+=1
02A611A1 | F3 0F 59 C1 | mulss xmm0,xmm1 | 两数相乘
02A611A5 | F3 0F 58 C3 | addss xmm0,xmm3 | xmm3的内容累加到xmm0
02A611A9 | 0F 28 D8 | movaps xmm3,xmm0 | xmm3存入本次运算结果
02A611AC | 3B 53 04 | cmp edx,dword ptr ds:[ebx+4] |
02A611AF | 7C AF | jl 2A61160 |
02A611B1 | 8B 5D F8 | mov ebx,dword ptr ss:[ebp-8] |
02A611B4 | 8B 4D FC | mov ecx,dword ptr ss:[ebp-4] |
02A611B7 | 8B 55 0C | mov edx,dword ptr ss:[ebp+C] |
02A611BA | 3B 3A | cmp edi,dword ptr ds:[edx] |
02A611BC | 7D 11 | jge 2A611CF |
02A611BE | 3B F3 | cmp esi,ebx |
02A611C0 | 7D 0D | jge 2A611CF |
02A611C2 | 8B 42 08 | mov eax,dword ptr ds:[edx+8] |
02A611C5 | 0F AF DF | imul ebx,edi |
02A611C8 | 03 DE | add ebx,esi |
02A611CA | F3 0F 11 1C 98 | movss dword ptr ds:[eax+ebx*4],xmm3 | 结果送00752618
02A611CF | 8B 5A 04 | mov ebx,dword ptr ds:[edx+4] |
02A611D2 | 46 | inc esi |
02A611D3 | 89 5D F8 | mov dword ptr ss:[ebp-8],ebx |
02A611D6 | 3B F3 | cmp esi,ebx |
02A611D8 | 0F 8C 72 FF FF FF | jl 2A61150 |
02A611DE | 47 | inc edi |
02A611DF | 3B 3A | cmp edi,dword ptr ds:[edx] |
02A611E1 | 0F 8C 5A FF FF FF | jl 2A61141 |
这里运算的结果是
1 0 3
0 6 0
-3 0 1
可以验证确实是矩阵乘法
接下来这个结果矩阵又和前面提到的第二个矩阵进行了加法运算:
02A61071 | 33 C9 | xor ecx,ecx |
02A61073 | 85 F6 | test esi,esi |
02A61075 | 7E 61 | jle 2A610D8 |
02A61077 | 3B 38 | cmp edi,dword ptr ds:[eax] |
02A61079 | 7D 16 | jge 2A61091 |
02A6107B | 8B 50 04 | mov edx,dword ptr ds:[eax+4] |
02A6107E | 3B CA | cmp ecx,edx |
02A61080 | 7D 0F | jge 2A61091 |
02A61082 | 8B 40 08 | mov eax,dword ptr ds:[eax+8] | eax:矩阵乘法结果地址
02A61085 | 0F AF D7 | imul edx,edi |
02A61088 | 03 D1 | add edx,ecx |
02A6108A | F3 0F 10 04 90 | movss xmm0,dword ptr ds:[eax+edx*4] | xmm0取上次结果矩阵的数
02A6108F | EB 03 | jmp 2A61094 |
02A61091 | 0F 28 C2 | movaps xmm0,xmm2 |
02A61094 | 8B 45 08 | mov eax,dword ptr ss:[ebp+8] |
02A61097 | 3B 38 | cmp edi,dword ptr ds:[eax] |
02A61099 | 7D 16 | jge 2A610B1 |
02A6109B | 8B 50 04 | mov edx,dword ptr ds:[eax+4] |
02A6109E | 3B CA | cmp ecx,edx |
02A610A0 | 7D 0F | jge 2A610B1 |
02A610A2 | 8B 40 08 | mov eax,dword ptr ds:[eax+8] | eax:第二个矩阵的地址
02A610A5 | 0F AF D7 | imul edx,edi |
02A610A8 | 03 D1 | add edx,ecx |
02A610AA | F3 0F 10 0C 90 | movss xmm1,dword ptr ds:[eax+edx*4] | xmm1取第二个矩阵的数
02A610AF | EB 03 | jmp 2A610B4 |
02A610B1 | 0F 28 CA | movaps xmm1,xmm2 |
02A610B4 | 3B 3B | cmp edi,dword ptr ds:[ebx] |
02A610B6 | 7D 15 | jge 2A610CD |
02A610B8 | 3B CE | cmp ecx,esi |
02A610BA | 7D 11 | jge 2A610CD |
02A610BC | 8B 43 08 | mov eax,dword ptr ds:[ebx+8] | eax:存结果的地址
02A610BF | F3 0F 58 C1 | addss xmm0,xmm1 | 两数相加
02A610C3 | 0F AF F7 | imul esi,edi |
02A610C6 | 03 F1 | add esi,ecx |
02A610C8 | F3 0F 11 04 B0 | movss dword ptr ds:[eax+esi*4],xmm0 | 存结果
02A610CD | 8B 73 04 | mov esi,dword ptr ds:[ebx+4] |
02A610D0 | 41 | inc ecx |
02A610D1 | 8B 45 FC | mov eax,dword ptr ss:[ebp-4] |
02A610D4 | 3B CE | cmp ecx,esi |
02A610D6 | 7C 9F | jl 2A61077 |
02A610D8 | 47 | inc edi |
02A610D9 | 3B 3B | cmp edi,dword ptr ds:[ebx] |
02A610DB | 7C 94 | jl 2A61071 |
为了接下来方便描述,这里用X代指输入生成的矩阵,A为第一个矩阵,B为第二个矩阵。那么刚刚的运算可以表示成:
C = X * A
D = C + B
而程序接下来又各调用了一次乘法和加法的函数,这次的运算对象有所改变,用算式表示如下:
E = A * A
F = E + X
接下来程序对D和F进行逐位比较,出现不等直接飞走
02A61890 | 33 C9 | xor ecx,ecx |
02A61892 | 83 FE 09 | cmp esi,9 |
02A61895 | 0F 8D C7 00 00 00 | jge 2A61962 |
02A6189B | 83 F9 03 | cmp ecx,3 |
02A6189E | 0F 8D BE 00 00 00 | jge 2A61962 |
02A618A4 | 8D 14 31 | lea edx,dword ptr ds:[ecx+esi] |
02A618A7 | F3 0F 10 0C 97 | movss xmm1,dword ptr ds:[edi+edx*4] |
02A618AC | 0F 2E CA | ucomiss xmm1,xmm2 |
02A618AF | 9F | lahf |
02A618B0 | F6 C4 44 | test ah,44 |
02A618B3 | 0F 8B A9 00 00 00 | jnp 2A61962 |
02A618B9 | F3 0F 10 04 93 | movss xmm0,dword ptr ds:[ebx+edx*4] |
02A618BE | 0F 2E C2 | ucomiss xmm0,xmm2 |
02A618C1 | 9F | lahf |
02A618C2 | F6 C4 44 | test ah,44 |
02A618C5 | 0F 8B 97 00 00 00 | jnp 2A61962 |
02A618CB | 0F 2E C8 | ucomiss xmm1,xmm0 |
02A618CE | 9F | lahf |
02A618CF | F6 C4 44 | test ah,44 |
02A618D2 | 0F 8A 8A 00 00 00 | jp 2A61962 |
02A618D8 | 41 | inc ecx |
02A618D9 | 83 F9 03 | cmp ecx,3 |
02A618DC | 7C B4 | jl 2A61892 |
02A618DE | 83 C6 03 | add esi,3 |
02A618E1 | 83 FE 09 | cmp esi,9 |
02A618E4 | 7C AA | jl 2A61890 |
那么到这里第一部分的分析结束,大致用算式表示一下就是:
X * A + B = A * A + X
其中A、B已知,求X
接下来是后半部分的算法分析:
首先在内存中放了一块这样的“数组”
07 01 04 00 03 08 02 05 06
由于是mov的直接数,觉得肯定是用上了,于是先记着
02A61350 | 0F BE 04 1F | movsx eax,byte ptr ds:[edi+ebx] | 取Name字符
02A61354 | 25 03 00 00 80 | and eax,80000003 | 模4
02A61359 | 79 05 | jns 2A61360 |
02A6135B | 48 | dec eax |
02A6135C | 83 C8 FC | or eax,FFFFFFFC |
02A6135F | 40 | inc eax |
02A61360 | 83 F8 03 | cmp eax,3 |
02A61363 | 77 3C | ja 2A613A1 |
02A61365 | FF 24 85 AC 13 A6 0 | jmp dword ptr ds:[eax*4+2A613AC] | switch 改变call的参数
02A6136C | 83 F9 02 | cmp ecx,2 |
02A6136F | 76 30 | jbe 2A613A1 |
02A61371 | 33 C9 | xor ecx,ecx | ecx清零
02A61373 | EB 21 | jmp 2A61396 |
02A61375 | 83 F9 08 | cmp ecx,8 |
02A61378 | 73 27 | jae 2A613A1 |
02A6137A | B9 01 00 00 00 | mov ecx,1 | ecx置1
02A6137F | EB 15 | jmp 2A61396 |
02A61381 | 83 F9 06 | cmp ecx,6 |
02A61384 | 73 1B | jae 2A613A1 |
02A61386 | B9 02 00 00 00 | mov ecx,2 | ecx置2
02A6138B | EB 09 | jmp 2A61396 |
02A6138D | 85 C9 | test ecx,ecx |
02A6138F | 74 10 | je 2A613A1 |
02A61391 | B9 03 00 00 00 | mov ecx,3 | ecx置3
02A61396 | E8 E5 FE FF FF | call 2A61280 |
02A6139B | 8B 0D 1C 3F A7 02 | mov ecx,dword ptr ds:[2A73F1C] |
02A613A1 | 47 | inc edi |
02A613A2 | 3B FE | cmp edi,esi |
02A613A4 | 72 AA | jb 2A61350 |
02A61280 | FF 24 8D F8 12 A6 0 | jmp dword ptr ds:[ecx*4+2A612F8] | switch 根据ecx选择处理方式
02A61287 | 8B 0D 1C 3F A7 02 | mov ecx,dword ptr ds:[2A73F1C] |
02A6128D | 8A 81 0D 3F A7 02 | mov al,byte ptr ds:[ecx+2A73F0D] |
02A61293 | 88 81 10 3F A7 02 | mov byte ptr ds:[ecx+2A73F10],al |
02A61299 | 83 E9 03 | sub ecx,3 |
02A6129C | 89 0D 1C 3F A7 02 | mov dword ptr ds:[2A73F1C],ecx |
02A612A2 | 83 F9 0A | cmp ecx,A | A:'\n'
02A612A5 | 73 08 | jae 2A612AF |
02A612A7 | C6 81 10 3F A7 02 0 | mov byte ptr ds:[ecx+2A73F10],0 |
02A612AE | C3 | ret |
02A612AF | E9 CC 08 00 00 | jmp 2A61B80 |
02A612B4 | 8B 0D 1C 3F A7 02 | mov ecx,dword ptr ds:[2A73F1C] |
02A612BA | 8A 81 11 3F A7 02 | mov al,byte ptr ds:[ecx+2A73F11] |
02A612C0 | 88 81 10 3F A7 02 | mov byte ptr ds:[ecx+2A73F10],al |
02A612C6 | 41 | inc ecx |
02A612C7 | EB D3 | jmp 2A6129C |
02A612C9 | 8B 0D 1C 3F A7 02 | mov ecx,dword ptr ds:[2A73F1C] |
02A612CF | 8A 81 13 3F A7 02 | mov al,byte ptr ds:[ecx+2A73F13] |
02A612D5 | 88 81 10 3F A7 02 | mov byte ptr ds:[ecx+2A73F10],al |
02A612DB | 83 C1 03 | add ecx,3 |
02A612DE | EB BC | jmp 2A6129C |
02A612E0 | 8B 0D 1C 3F A7 02 | mov ecx,dword ptr ds:[2A73F1C] |
02A612E6 | 8A 81 0F 3F A7 02 | mov al,byte ptr ds:[ecx+2A73F0F] |
02A612EC | 88 81 10 3F A7 02 | mov byte ptr ds:[ecx+2A73F10],al |
02A612F2 | 49 | dec ecx |
02A612F3 | EB A7 | jmp 2A6129C |
可以看到这两段代码通过Name字符的ASCII码值对上面的字串进行了一定的操作
具体操作就是将0的位置和四个可选位置数的值进行了替换
观察可以发现(上面一段的函数里有线索)其实还是个3 * 3的矩阵
7 1 4
0 3 8
2 5 6
四个位置自然也就是上下左右,360对应ASCII是0x33,0x36,0x30
模4后分别是3、2、0
而矩阵的变化是先4 0交换
然后8 0交换,最后还是8 0交换
所以可知3表示0左移,2表示下移,0表示上移,剩下的1也就是0右移
然后。。看到这就已经想到拼图游戏了。。0表示的是空位那种
接下来的代码又开始跳到那一段位移的函数了,算法如下:
02A61910 | 0F BE 4C 05 B4 | movsx ecx,byte ptr ss:[ebp+eax-4C] | 取Serial后半段一个字符
02A61915 | 8D 41 D0 | lea eax,dword ptr ds:[ecx-30] | 去掉30,取数字部分
02A61918 | 83 F8 08 | cmp eax,8 | 和8比较
02A6191B | 77 08 | ja 2A61925 | 大于跳
02A6191D | 83 C1 D0 | add ecx,FFFFFFD0 | 不还是-0x30吗。。
02A61920 | E8 9B FA FF FF | call 2A613C0 |
02A61925 | 80 C3 01 | add bl,1 |
02A61928 | 0F B6 C3 | movzx eax,bl |
02A6192B | 3B C6 | cmp eax,esi |
02A6192D | 72 E1 | jb 2A61910 |
函数2A613C0内:
02A613C0 | B8 56 55 55 55 | mov eax,55555556 | eax置0x55555556
02A613C5 | F7 E9 | imul ecx | ecx是输入数,与eax相乘
02A613C7 | 56 | push esi |
02A613C8 | 8B F2 | mov esi,edx | edx给esi(imul后edx:eax存结果)
02A613CA | C1 EE 1F | shr esi,1F | esi右移0x1F位
02A613CD | 03 F2 | add esi,edx | esi += edx
02A613CF | 8D 04 76 | lea eax,dword ptr ds:[esi+esi*2] | eax = esi + esi * 2
02A613D2 | 2B C8 | sub ecx,eax | ecx = ecx - eax
02A613D4 | 83 FE 02 | cmp esi,2 |
02A613D7 | 7F 70 | jg 2A61449 |
02A613D9 | 83 F9 02 | cmp ecx,2 |
02A613DC | 7F 6B | jg 2A61449 |
02A613DE | 03 C1 | add eax,ecx | eax = eax + ecx
02A613E0 | 80 B8 10 3F A7 02 0 | cmp byte ptr ds:[eax+2A73F10],0 |
02A613E7 | 74 60 | je 2A61449 |
02A613E9 | 83 F8 02 | cmp eax,2 |
02A613EC | 7E 14 | jle 2A61402 |
02A613EE | 80 B8 0D 3F A7 02 0 | cmp byte ptr ds:[eax+2A73F0D],0 |
02A613F5 | 75 0B | jne 2A61402 |
02A613F7 | B9 02 00 00 00 | mov ecx,2 | ecx置2
02A613FC | 5E | pop esi |
02A613FD | E9 7E FE FF FF | jmp 2A61280 |
02A61402 | 83 F9 02 | cmp ecx,2 |
02A61405 | 7D 14 | jge 2A6141B |
02A61407 | 80 B8 11 3F A7 02 0 | cmp byte ptr ds:[eax+2A73F11],0 |
02A6140E | 75 0B | jne 2A6141B |
02A61410 | B9 03 00 00 00 | mov ecx,3 | ecx置3
02A61415 | 5E | pop esi |
02A61416 | E9 65 FE FF FF | jmp 2A61280 |
02A6141B | 83 FE 02 | cmp esi,2 |
02A6141E | 7D 11 | jge 2A61431 |
02A61420 | 80 B8 13 3F A7 02 0 | cmp byte ptr ds:[eax+2A73F13],0 |
02A61427 | 75 08 | jne 2A61431 |
02A61429 | 33 C9 | xor ecx,ecx | ecx清零
02A6142B | 5E | pop esi |
02A6142C | E9 4F FE FF FF | jmp 2A61280 |
02A61431 | 85 C9 | test ecx,ecx |
02A61433 | 7E 14 | jle 2A61449 |
02A61435 | 80 B8 0F 3F A7 02 0 | cmp byte ptr ds:[eax+2A73F0F],0 |
02A6143C | 75 0B | jne 2A61449 |
02A6143E | B9 01 00 00 00 | mov ecx,1 | ecx置1
02A61443 | 5E | pop esi |
02A61444 | E9 37 FE FF FF | jmp 2A61280 |
02A61449 | 5E | pop esi |
02A6144A | C3 | ret |
这里解释一下算法:
首先取输入的数字,ASCII->Number后传入函数
函数内首先将数字处理成3 * x + y的形式
esi存放x(乘数),ecx存放y(余数),eax存放3 * x(02A613DE之前)以及原数字(02A613DE之后,判断用这个)
然后程序根据这三个寄存器的值进行判断如何进行位移
给出的Serial运行完后内存变成了这样:
02A73F10 01 02 03 04 05 06 07 08 00 00 00 00 08 00 00 00 ...........
前八位变成了按顺序排列,后面的代码也是在验证这一点:
02A61931 | 0F B6 CA | movzx ecx,dl |
02A61934 | 8A 81 10 3F A7 02 | mov al,byte ptr ds:[ecx+2A73F10] |
02A6193A | 3A 81 0F 3F A7 02 | cmp al,byte ptr ds:[ecx+2A73F0F] |
02A61940 | 7C 07 | jl 2A61949 |
02A61942 | FE C2 | inc dl |
02A61944 | 80 FA 08 | cmp dl,8 |
02A61947 | 72 E8 | jb 2A61931 |
也就是说最终目标是使得给出的矩阵的前八位变成顺序排列即可
那么还有一种方式可以通过验证,即012345678
分析到此完毕~ 去年太水还做不出,这两天想起来于是把题目肝了下来Orz