170617 逆向-CrackMe之024

来源:互联网 发布:青果软件教务系统 编辑:程序博客网 时间:2024/05/14 06:57

1625-5 王子昂 总结《2017年6月17日》 【连续第258天总结】

A.CrackMe(24)

B.这个CM做了好几天了,第一次见到自己修改自己指令的判断,还是挺懵的

放到PEiD里监测显示是MASM,纯汇编写的程序能玩的花样就比编译器制造的多得多了

首先在OD中运行,总是跳到奇奇怪怪的命令里去

尝试放到IDA中反汇编,只出现了窗口相关的代码,在最后只知道进入了某个函数中进行处理,却完全没有相关代码

没办法,只好回到OD中单步跟


004012E9   .^ 74 EE         je short Chafe_2.004012D9                ;  关键跳
004012EB   >  68 59304000   push Chafe_2.00403059                    ; /Your serial is not valid.

很明显NOP掉关键跳是不行的,观察004012D9的代码发现都不是指令,显然简单的修改为jmp也是不行的

再往下看

00401301   .  68 73 30 40 0>ascii "hs0@",0                           ;  YES! You found your serial!!
00401306   .  FF35 5C314000 push dword ptr ds:[0x40315C]             ; |hWnd = 16A4312E ('Your serial is not valid.',class='Edit',parent=11283162)
0040130C   .  E8 67010000   call <jmp.&USER32.SetWindowTextA>        ; \SetWindowTextA
00401311   .  33C0          xor eax,eax
00401313   .  C9            leave
00401314   .  C2 1000       retn 0x10

这里是正确提示,那么jmp 00401301试试,爆破成功

注册机

首先是将name的每4个字节的ASCII累加,循环16次,再加上固定数0x58455443

然后将结果加上Serial转化成INT型的值

跟着继续看:004012BB   .  3105 D9124000 xor dword ptr ds:[0x4012D9],eax          

这一行命令与常见的不同,它修改的是指令的值(而不是寄存器或是存储变量区域的值)

接下来会运行到D9的命令,因此这个地方很关键

那么应该修改成什么样呢?暂且不管,看下面的未经修改的命令是什么:

004012CB   .  BE EC114000   mov esi,Chafe_2.004011EC
004012D0   .  B9 3E000000   mov ecx,0x3E
004012D5   .  33DB          xor ebx,ebx
004012D7   .  EB 04         jmp short Chafe_2.004012DD
004012D9   >  54            push esp                                 ;  改变
004012DA      45            db 45                                    ;  CHAR 'E'
004012DB      58            db 58                                    ;  CHAR 'X'
004012DC      00            db 00
004012DD   >  AD            lods dword ptr ds:[esi]                  ;  跳转到这里
004012DE   .  33D8          xor ebx,eax
004012E0   .  49            dec ecx                                  ;  user32.76C946F6
004012E1   .^ 75 FA         jnz short Chafe_2.004012DD               ;  从4011EC到4011EC+0x3E,每个4字节与bx异或

004012E3   .  81FB FBCFFCAF cmp ebx,0xAFFCCFFB                       ;  结果若为0xAFFCCFFB则成功

004012E9   .^\74 EE         je short Chafe_2.004012D9                ;  关键跳



最终关键跳前方是将ebx与一个数比较,相等则跳至004012D9

那么再看ebx怎么来的,lods指令是将esi处的数据送至eax中,那么这个循环的功能就很明显了:

从4011EC到4011EC+0x3E,每个4字节与bx异或

既然比较成功了跳的是4012D9,那么很明显,4012D9处的指令应该被修改为跳至成功提示的指令

直接修改试试,爆破成功。并且此时可以看到,4012D9的机器码为EB 26

之后4012DB和DC的机器码就应该由最终的异或判断确定了

由于异或的逆运算还是异或,即只要将结果与一个运算数异或就能得到另一个运算数

观察确认会改变的机器码只有4012D9-4012DC的4个字节,也就是4012D8开始的后三个字节和4012DC的第一个字节

将4011EC到4011D4的机器码全部复制下来

刨掉这两个四字节,将前后两部分数据分别异或,脚本为:

a=[0x55,0x8B,0xEC,0x83,0xC4,0xFC,0x8B,0x45,0x0C,0x83,0xF8,0x10,0x75,0x0D,0x6A,0x00,0xE8,0x6B,0x02,0x00,0x00,0x33,0xC0,0xC9,0xC2,0x10,0x00,0x83,0xF8,0x0F,0x75,0x0E,0x8B,0x45,0x08,0xE8,0x18,0x01,0x00,0x00,0x33,0xC0,0xC9,0xC2,0x10,0x00,0x83,0xF8,0x01,0x75,0x06,0x33,0xC0,0xC9,0xC2,0x10,0x00,0x3D,0x11,0x01,0x00,0x00,0x0F,0x85,0xE7,0x00,0x00,0x00,0x8B,0x45,0x14,0x3B,0x05,0x60,0x31,0x40,0x00,0x75,0x1A,0x6A,0x00,0x68,0x96,0x30,0x40,0x00,0x68,0xA7,0x30,0x40,0x00,0xFF,0x75,0x08,0xE8,0x17,0x02,0x00,0x00,0x33,0xC0,0xC9,0xC2,0x10,0x00,0x3B,0x05,0x58,0x31,0x40,0x00,0x74,0x0C,0x3B,0x05,0x54,0x31,0x40,0x00,0x0F,0x85,0xAE,0x00,0x00,0x00,0xC7,0x05,0xD9,0x12,0x40,0x00,0x54,0x45,0x58,0x00,0x6A,0x00,0x8D,0x45,0xFC,0x50,0x6A,0x64,0xFF,0x35,0x50,0x31,0x40,0x00,0xE8,0xBC,0x01,0x00,0x00,0x83,0x7D,0xFC,0x00,0x74,0x5F,0x50,0x6A,0x14,0x68,0x6C,0x31,0x40,0x00,0xFF,0x35,0x54,0x31,0x40,0x00,0xE8,0xAF,0x01,0x00,0x00,0x85,0xC0,0x74,0x48,0xA1,0x0B,0x30,0x40,0x00,0xBB,0x6C,0x31,0x40,0x00,0x03,0x03,0x43,0x81,0xFB,0x7C,0x31,0x40,0x00,0x75,0xF5,0x5B,0x03,0xC3,0x31,0x05,0xD9,0x12,0x40,0x00,0xC1,0xE8,0x10,0x66,0x29,0x05,0xD9,0x12,0x40,0x00,0xBE,0xEC,0x11,0x40,0x00,0xB9,0x3E,0x00,0x00,0x00,0x33,0xDB,0xEB]f=0s=0x=0for i in a:    s=s+i*(2**(f*8))    if(f==3):        x=x^s        f=0        s=0    else:        f=f+1
print(hex(x))

得到结果:0xa213fcee

再与最后一部分的值0x81fa7549和最终结果0xAFFCCFFB异或,得到:

0x8c15465c

这就是中间两个四字节04 xx xx xx || xx ad 33 d8异或的结果

那么中间四个字节怎么求呢?由于我们之前已经推算出004012D9的机器码必须为EB 26,因此前两个xx就已知了

而因为异或是按位的,因此虽然运算数是两个四字节,但四字节的高低位之间可以单独对应进行异或,即:

04 eb 26 xx

xx ad 33 d8

异或得到

5c 46 15 8c

则5c和04异或可以得到第一个xx,为58

8c和d8异或可以得到最后一个xx,为54

这样就得到了中间的修改结果:eb 26 54 58

再向上逆推,NAME处理后的值+SERIAL整型值(设为X),与原004012D9的值异或,再减去X的高四位,得到0x585426eb

原004012D9的值是0x00584554

整理算法,X^0x00584554-X的高四位=0x585426eb

同理,由于异或是按位的,因此可以将四字节数值拆分单独进行异或

由于0x585426eb加的是一个四位数,因此高四位必然是0x5854(或进位为0x5855,下面说),那么只需要与运算数0x00584554的高四位进行异或就能得到X的高四位了,运算得0x580c

PS:如果将高四位当做0x5855,异或得到0x580d,验算0x580d+0x26eb并不会进位,因此舍去这种情况

那么第四位26eb+0x580c的结果与X的第四位异或应该等于0x4554

逆运算得0x3ba3

这样就能得到X=0x45543ba3了

这样只要用X-NAME处理后的值就能得到SERIAL了

事实上,由于基准数0x58455443是大于最终结果0x45543ba3的,因此肯定要出现超出32位寄存器取值范围的情况,这种时候由于python是不会自动进行调整的,因此需要自己在脚本中修正

脚本为:

s=input()+chr(0)*20#补足字符串的长度a=0x58455443for i in range(16):    a=a+ord(s[i])+ord(s[i+1])*0x100+ord(s[i+2])*0x10000+ord(s[i+3])*0x1000000k=0x580c3ba3-awhile(k<0):#当作差后的值为负数时用补码求法来修正    k=0xffffffff+k+1print(k)
这样注册机就做成了
验证成功

C.明日计划

计算思维(如果还有的话


原创粉丝点击