《加密与解密》个人阅读笔记 五

开场

嘿耶耶耶~~~~ c↗s→d↗n→的朋↗↘友
在这里插入图片描述
非常~非常~期待 我们很快就要见~面~~~

序列号保护机制

序列号保护机制在软件中很常见,一些软件如果没有经过验证会有使用时间和使用功能的限制,需要用户输入个人信息,或者付费解锁。例如使用正版的mathtype需要到官网购买序列号,不然只能使用一个月,而且还不能使用全部的功能。

破解serial.exe的详细步骤

先打开序列号验证程序,观察程序验证流程
在这里插入图片描述
随便输入用户名和序列号后,出现了错误提示Incorrect!Try Again
打开od,右键->查找->所有参考文本字串
在这里插入图片描述
双击Incorrect!,Try Again,跳转到对应的代码处。
在这里插入图片描述
这段代码用于弹出失败窗口,那么就向上翻阅,查找关键代码
在这里插入图片描述
GetDlgItemText这个API用于获取用户输入的字符串,这个函数被调用了两次,获取的内容分别放在0040218E0040217E中,可以推测存放的是用户名以及序列号。注意:这里的count对输入字符的最大个数有规定

接着向上查找,很容易找到序列号验证算法

00401228   .  68 8E214000   push serial.0040218E                     ;  ASCII "sorry"
0040122D   .  E8 4C010000   call serial.0040137E
00401232   .  50            push eax
00401233   .  68 7E214000   push serial.0040217E                     ;  ASCII "penny"
00401238   .  E8 9B010000   call serial.004013D8
0040123D   .  83C4 04       add esp,0x4
00401240   .  58            pop eax                                  ;  serial.00401232
00401241   .  3BC3          cmp eax,ebx                              ;  serial.WndProc
00401243   .  74 07         je short serial.0040124C
00401245   .  E8 18010000   call serial.00401362
0040124A   .^ EB 9A         jmp short serial.004011E6
0040124C   >  E8 FC000000   call serial.0040134D
00401251   .^ EB 93         jmp short serial.004011E6


这段代码将40218E40217E处的内容弹如栈,基本可以确定是验证算法了
该处代码先将40137E的返回值k1放入寄存器eax,利用寄存器将k1作为004013D8处函数的参数,这个函数应该会将结果放入ebx,这里将结果记为k2。然后就是比较k1k2的值(eax 和ebx的值),一样的话就成功验证了:)

按下f2打下断点,运行程序
在这里插入图片描述
点击OK,程序运行到了断点处,如下图
在这里插入图片描述

进入到40137E函数中
在这里插入图片描述
看第一段代码mov esi,dword ptr ss::[esp + 0x4] ,首先要明白[esp+0x4]是个什么东西。看右侧的寄存器窗口,esp的值为0019FDB0。观察右下角的窗口,可以观察到0019FDB4对应我们输入的用户名

这段验证代码可以分成几个部分来看
第一部分:验证输入的字符是不是大写字母(大写字母的ASCII编码对应十六进制为0x41–0x5A)

0040137E  /$  8B7424 04     mov esi,dword ptr ss:[esp+0x4]           ;  serial.0040218E
00401382  |.  56            push esi
00401383  |>  8A06          /mov al,byte ptr ds:[esi]
00401385  |.  84C0          |test al,al
00401387  |.  74 13         |je short serial.0040139C
00401389  |.  3C 41         |cmp al,0x41
0040138B  |.  72 1F         |jb short serial.004013AC
0040138D  |.  3C 5A         |cmp al,0x5A    //如果是小写字母,要特殊处理,这里没有专门分析
0040138F  |.  73 03         |jnb short serial.00401394
00401391  |.  46            |inc esi
00401392  |.^ EB EF         |jmp short serial.00401383
00401394  |>  E8 39000000   |call serial.004013D2
00401399  |.  46            |inc esi
0040139A  |.^ EB E7         \jmp short serial.00401383
0040139C  |>  5E            pop esi                                  ;  serial.00401232
0040139D  |.  E8 20000000   call serial.004013C2

分析一下这串代码:

  • 使用mov al,byte ptr ds:[esi]存下esi寄存器的第一个字符,为什么是一个字符呢?因为al是一个8位的通用寄存器,而扩展的ASCII码用8个二进制位表示字符。
  • 因为al指向的是esi寄存器的第一个字符,所以当esi没有内容时,test al al会将零标志位设为1,然后程序跳转到0040139C,结束比较
  • inc esi 的作用是去掉esi的第一个字符(可以看OD右侧的寄存器窗口验证)。在这个过程中,esi寄存器的值是一直变化的。

接下来分析调用的004013C2的函数

004013C2  /$  33FF          xor edi,edi
004013C4  |.  33DB          xor ebx,ebx
004013C6  |> /8A1E          /mov bl,byte ptr ds:[esi]
004013C8  |. |84DB          |test bl,bl
004013CA  |. |74 05         |je short serial.004013D1
004013CC  |. |03FB          |add edi,ebx
004013CE  |. |46            |inc esi                                 ;  serial.0040218F
004013CF  |.^\EB F5         \jmp short serial.004013C6
004013D1  \>  C3            retn

这段代码把用户名每一个字符对应的十六进制ASCII编码加到edi
在这里插入图片描述
然后将这个数异或0x5678,结果放在eax寄存器中。

接下来看一看处理序列号的函数
在这里插入图片描述
和上面的处理差不多:)
这里要注意顺序:imul的操作对象是edi,sub的操作对象是bl

使用书中的keygen 完成解密

int keygen(char *name) 
{
	int i,k1=0,k2=0;
	char ch;
	for(i=0;name[i]!=0&&i<=9;i++) 
	{
		ch=name[i];
		if(ch<'A'break;
		k1+=(ch>'Z')?(ch-32):ch; //异或运算是可逆的
	}
	k2=k1^0x5678^0x1234;//这里的k2是以十进制形式表示的,直接将其输出,就得到了序列号
	return k2;
}

休息一下
               ↓ 班级里那位最喜欢抢风头的人 b e   l i k e : ~~~~~~~~~~~~~~↓班级里那位最喜欢抢风头的人be~like:               班级里那位最喜欢抢风头的人be like:
在这里插入图片描述
研究春山学,不比研究ctf有趣?
休息结束,还是得继续看逆向:(


去掉警告窗口

先尝试运行程序吧
在这里插入图片描述
这次的目标是要去掉弹出的窗口

目前我们遇到了两个能够弹出窗口的API。一个是MessageBox,另外一个是这次遇到的DialogBoxParam

在这里插入图片描述

API文档是这样介绍DialogBoxParam的第二个参数IpTemplateName的:该字符串指定对话框模扳名,或是指定对话框模板的资源标识符的一个整型值。

由于这个程序是使用资源来显示对话框的,可以使用resource hacker观察这个对话框。0x79的十进制数为121
在这里插入图片描述
但我们需要修改代码,并不仅仅满足于观察对话框。可以使用OD修改代码。思路就是使用jmp跳过弹出窗口的函数。由于DialogBoxParam是和EndDialog配套出现的,所以我们要把整个过程都跳过。
在这里插入图片描述
但是这里出现了两个EndDialog函数,为了确认哪一个是关闭这个窗口的,可以尝试调试代码看看
我分别在004010A2处和004010D9处下断点,接着运行程序,点击弹出窗口多的ok按钮,程序断在D9处
在这里插入图片描述
那么将“00401051 push 00000000”改成“00401051 jmp 4010E5"。
右键->汇编,输入jmp 004010E5
然后保存流程如下
在这里插入图片描述

这个窗口就不会弹出来啦:)

拆除时间限制

先运行程序看看
在这里插入图片描述
看起来程序只能运行20秒,过了就会自动关闭
在这里插入图片描述
这个函数的参数Timeproc为NULL,说明超时了会向对应窗口发送WM_TIMER信息。
那只要跳过这个函数的调用就行了:)

在这里插入图片描述
更改如上,这个软件的时间限制就被我们去掉了。

keyFile保护

这竟然是上个世纪的软件,长见识了
首先还是运行软件看看
在这里插入图片描述
这个对话框里面的内容没办法更改,点击Check按钮也没有反应
打开od看看,可以根据下方对话框的名称确定弹出窗口的API
在这里插入图片描述
这次弹出窗口的API是CreatWindowEx,文档说这是一个用来弹出窗口的函数。打了断点验证,确实如此,后面的ShowWindow等函数用来确定窗口的样式。

有一个问题。。我按下f8单步步过调试程序,这个程序一直在40129A401275之间跳转,我不知道怎么确定4016D9CreatFileA就是关键代码

那么就按照书中的操作来吧:在4016D9打下断点,接着运行程序,点击Check按钮,之后OD果然在这里停住了
在这里插入图片描述

cmp eax -0x1 是什么意思呢?在msdn里查找CreatFile的文档
在这里插入图片描述
INVALID_HANDLE_VALUE是一个宏定义,值为-1。

如果我们没有创建KwazyWeb.bit文件,程序会跳转到401747处,验证失败。
WinHex创建一个十六进制文件,将其保存到程序目录下,尽量写的有规律一点,这样用比较容易通过代码找到规律
在这里插入图片描述


我已经在4016D9打下断点了,接下来尝试分析程序

在这里插入图片描述CreatFile函数运行成功后,返回KwazyWeb.bit的可执行句柄,放在内存403444处(这个地址可能会变),值为5B4。

中间的ReadFile函数有参数hFile=005B4,表示读取这个文件的内容。这段代码将KwazyWeb.bit的第一个字节放在Buffer处,并使用test语句判断是否为0。
所以这段代码用于判断文件是否为空,如果为空就跳转 (两个十六进制数表示一个字节)

在这里插入图片描述

以此类推,这次的Buffer缓冲区存放从第二个开始,共eax个字节(这里是02 03 04 05)(因为我重启了od,所以存放数据的位置改变了,不过函数功能和位置不会改变

分析401000的函数

00401006  |.  8A0D FA344000 mov cl,byte ptr ds:[0x4034FA] //存放文件的第一个字节
0040100C  |.  BE 88324000   mov esi,PacMe.00403288 //文件第二---eax-1字节
00401011  |>  AC            /lods byte ptr ds:[esi]
00401012  |.  03D0          |add edx,eax
00401014  |.^ E2 FB         \loopd short PacMe.00401011
00401016  |.  8815 FB344000 mov byte ptr ds:[0x4034FB],dl
0040101C  \.  C3            retn

KwazyWeb.bit文件的第二个字节开始读取数据并求和,数量为第一个字节的值,然后把它放到4034FB

看下一个ReadFile函数
在这里插入图片描述
这个函数读取接下来的18个十六进制字符到内存004034E8中。然后调用关键函数004010C9,分析一下这个函数

004010C9  /$  55            push ebp
004010CA  |.  8BEC          mov ebp,esp
004010CC  |.  83C4 FC       add esp,-0x4
004010CF  |.  68 65334000   push PacMe.00403365                      ; /String2 = "****************C*......*...****.*.****...*....*.*..**********.*..*....*...*...**.****.*.*...****.*....*.*******..*.***..*.....*.*..***.**.***.*...****....*X..*****************"
004010D4  |.  68 BC314000   push PacMe.004031BC                      ; |String1 = PacMe.004031BC
004010D9  |.  E8 3A070000   call <jmp.&KERNEL32.lstrcpyA>            ; \lstrcpyA
004010DE  |.  C705 84314000>mov dword ptr ds:[0x403184],PacMe.004031>;  ASCII "C*......*...****.*.****...*....*.*..**********.*..*....*...*...**.****.*.*...****.*....*.*******..*."
//403184存放字符C的地址004031CC

004010E8  |.  E8 30FFFFFF   call PacMe.0040101D //处理第三次读取的十八个字节
004010ED  |.  C645 FE 00    mov byte ptr ss:[ebp-0x2],0x0
004010F1  |.  33C0          xor eax,eax                              ;  PacMe.004031BC
004010F3  |.  33C9          xor ecx,ecx

(存放字符C的地址)在这里插入图片描述


接着分析40101D函数吧

0040101D  /$  8A15 FB344000 mov dl,byte ptr ds:[0x4034FB]
00401023  |.  B9 12000000   mov ecx,0x12
00401028  |.  B8 E8344000   mov eax,PacMe.004034E8
0040102D  |>  3010          /xor byte ptr ds:[eax],dl
0040102F  |.  40            |inc eax                                 ;  PacMe.004031BC
00401030  |.^ E2 FB         \loopd short PacMe.0040102D
00401032  \.  C3            retn

这段代码就是简单的异或,将第三次读取的十八个字节异或上401000函数中累加的值。


再分析一下函数返回后的代码

004010ED  |.  C645 FE 00    mov byte ptr ss:[ebp-0x2],0x0 //x=0
004010F1  |.  33C0          xor eax,eax                              ;  PacMe.004034FA
004010F3  |.  33C9          xor ecx,ecx
004010F5  |>  C645 FF 08    /mov byte ptr ss:[ebp-0x1],0x8 // len = 8
004010F9  |>  806D FF 02    |/sub byte ptr ss:[ebp-0x1],0x2 // len -=2
004010FD  |.  0FB64D FE     ||movzx ecx,byte ptr ss:[ebp-0x2] //ecx = x
00401101  |.  81C1 E8344000 ||add ecx,PacMe.004034E8  // ecx为004034E8后移x字节的值
00401107  |.  8A01          ||mov al,byte ptr ds:[ecx]    
00401109  |.  8A4D FF       ||mov cl,byte ptr ss:[ebp-0x1]
0040110C  |.  D2E8          ||shr al,cl // al>>cl
0040110E  |.  24 03         ||and al,0x3  //al &&11  看起来是要处理eax的数据
00401110  |.  E8 1EFFFFFF   ||call PacMe.00401033
00401115  |.  85C0          ||test eax,eax                           ;  PacMe.004034FA
00401117  |.  74 11         ||je short PacMe.0040112A  // 退出循环
00401119  |.  0FB655 FF     ||movzx edx,byte ptr ss:[ebp-0x1] 
// tmp的初值为8,每一次都会-2,所以应该会循环4次,这是小循环
0040111D  |.  85D2          ||test edx,edx                           ;  PacMe.0040340E
0040111F  |.^ 75 D8         |\jnz short PacMe.004010F9
00401121  |.  FE45 FE       |inc byte ptr ss:[ebp-0x2] // x++ 
00401124  |.  807D FE 12    |cmp byte ptr ss:[ebp-0x2],0x12 // 大循环要循环18次
00401128  |.^ 75 CB         \jnz short PacMe.004010F5
0040112A  |>  C9            leave
0040112B  \.  C3            retn

这是401033函数的代码

00401033   $  55            push ebp
00401034   .  8BEC          mov ebp,esp
00401036   .  83C4 F8       add esp,-0x8
00401039   .  8B15 84314000 mov edx,dword ptr ds:[0x403184]          ;  PacMe.004031CC
0040103F   .  8955 FC       mov dword ptr ss:[ebp-0x4],edx           ;  PacMe.0040340E
//字符`c`的地址保存在[ebp-0x4]中
// al =0
00401042   .  0AC0          or al,al                                 ;  Switch (cases 0..2)
00401044   .  75 09         jnz short PacMe.0040104F
//-16
00401046   .  832D 84314000>sub dword ptr ds:[0x403184],0x10         ;  Case 0 of switch 00401042
0040104D   .  EB 1F         jmp short PacMe.0040106E
0040104F   >  3C 01         cmp al,0x1
00401051   .  75 08         jnz short PacMe.0040105B
//+1
00401053   .  FF05 84314000 inc dword ptr ds:[0x403184]              ;  PacMe.004031CC; Case 1 of switch 00401042
00401059   .  EB 13         jmp short PacMe.0040106E
0040105B   >  3C 02         cmp al,0x2
0040105D   .  75 09         jnz short PacMe.00401068
//+16
0040105F   .  8305 84314000>add dword ptr ds:[0x403184],0x10         ;  Case 2 of switch 00401042
00401066   .  EB 06         jmp short PacMe.0040106E
//-1
00401068   >  FF0D 84314000 dec dword ptr ds:[0x403184]              ;  PacMe.004031CC; Default case of switch 00401042
0040106E   >  8B15 84314000 mov edx,dword ptr ds:[0x403184]          ;  PacMe.004031CC
00401074   .  8A02          mov al,byte ptr ds:[edx]
00401076   .  3C 2A         cmp al,0x2A
00401078   .  75 06         jnz short PacMe.00401080
0040107A   .  33C0          xor eax,eax
0040107C   .  C9            leave
0040107D   .  C3            retn

这段代码开始我们就能推测出程序加密原理了。[0x403184] 中存放字符C的地址,那么地址+1 -1可以分别认为C向右移动和向左移动。那么+16 -16就理所当然是向下和向上移动了。回头看之前出现过的奇怪字符串,如果把16个字符分为一行,结果就是这样:

****************
C*......*...****
.*.****...*....*
.*..**********.*
..*....*...*...*
*.****.*.*...***
*.*....*.*******
..*.***..*.....*
.*..***.**.***.*
...****....*X..*
****************

如果把这个看成一个迷宫,C当成玩家,盲猜.表示可以走的路,X表示终点。(使用瞪眼法秒了!)
路径如下:下下下右下下下左下下右右上右上上右右右上上左左左上左上上右右右右右下右右上右右下右右右下下左左下左左上左左下下下左下下右右右上上右右右右下下左左(一共是72步,正好是18*4)

第三次获取的数据有18个字节,每一个字节都确定接下来4步怎么走。第一个字节决定1至4步的走法,第二个字节决定5至8步的走法,以此类推。(18个字节都是被异或过的)

将异或之后的某一字节用x表示,用(x>>6)&0x3决定第一步的走法 ,结果为x的最高两位(7,8位)
(x>>4)&0x3决定第二步的走法 ,结果为x的第5,6两位,剩下的以此类推。每一步都可以对应一个两位的二进制数(转换成十进制范围为0--3):0表示向上,1表示向右,2表示向下,3表示向左

将路径用四进制表示,结果如下:
在这里插入图片描述
变成十六进制,结果如下 A9 AB A5 10 54 3F 30 55 65 16 56 BE F3 EA E9 50 55 AF

写一个python代码得出结果

    data = [0xA9, 0xAB, 0xA5, 0x10, 0x54, 0x3F, 0x30, 0x55, 0x65, 0x16, 0x56, 0xBE, 0xF3, 0xEA, 0xE9, 0x50, 0x55, 0xAF]

for i in data:
    print(hex(i^0x1),end= " ")

在这里插入图片描述
成功验证:)
在这里插入图片描述


本文结束,网络验证就不看了,等之后学习了网络编程再说吧
接下来是与本文无关的一些废话:)


后记

好难。。真的好难。。导师说寒假要看《加密与解密》的,现在寒假快结束了,连一半都没看完。。。

请添加图片描述
照例的meme时间
发现马上要开学了,不能一觉睡到中午十二点的我be like↓
在这里插入图片描述
猫猫可爱,猫好
人发猫猫丑图,人坏!

在这里插入图片描述

  • 30
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值