汇编指令学习

更新时间:2023-12-16 09:57:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

1.ASCii表(基础)

2.对特殊汇编指令讲解(推荐)

3.定位程序注册代码段

一、ASCII表

◇数 字类:

数 字 0 1 2 3 4 5 6 7 8 9 十六进制 30 31 32 33 34 35 36 37 38 39 十 进制 48 49 50 51 52 53 54 55 56 57

◇大写字母:

字 母 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 十六进制 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 十 进制 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

◇小写字母:

小写字母 a b c d e f g h i j k l m n o p q r s t u v w x y z 十六进制 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 十 进制 97 98 99 100101102103104105106107108109110111112113114115116117118119120121122

◇特殊字符:

字 符 ! \_ ` { | } ~

十六进制 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 3A 3B 3C 3D 3E 3F 40 5B 5C 5D 5E 5F 60 7B 7C 7D 7E

十 进制 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 58 59 60 61 62 63 64 91 92 93 94 95 96123124125126

=>记忆技巧<=

数 字:'0'~'9' -> 31~39 大写字母:'A'~'Z' -> 41~5A 小写字母:'a'~'z' -> 61~7A

特别字符:空 格' ' -> 20 连字符'-' -> 2D

备注:连字符在序列号中经常用到,应熟记

■对字符的ASCII值一定要熟悉,深入分析非密码学算法的关键 很多算法是在字符的ASCII值上\做文章\的

#举个典型的例子 算法描述如下:

->取用户名每个字符的ASCII值,累加以后做为序列号 示例代码

004B32BB |> 8B4D F0 /mov ecx, dword ptr [ebp-10] ; ASCII \

004B32BE |. 8A0C01 |mov cl, byte ptr [ecx+eax] ; 004B32C1 |. 81E1 FF000000 |and ecx, 0FF ; 004B32C7 |. 0FAFC8 |imul ecx, eax ; ECX = ECX * EAX 004B32CA |. 03F9 |add edi, ecx ; EDI = EDI + ECX 004B32CC |. 40 |inc eax ; EAX++ 004B32CD |. 4A |dec edx ; EDX--

004B32CE |.^ 75 EB \\jnz short 004B32BB ; 次

■大写小写转化

大写 -> 小写: 加20H 小写 -> 大写: 减20H

■另外,还要对一下知识有一定了解

1.数值的十进制和16进制转化 2.字符直接变数字 3.数字直接变字符 4....

二、汇编指令

1.数据传送(Data transfer) 2.算术运算(Arithmetic)

3.逻辑运算和移位指令(Logic& Shift) 4.串操作(String manipulation) 5.控制转移(Control Transfer) 6.处理器控制(Processor Control)

具体查阅8086系统指令手册

字符串的第i个字符取cl

循环length(string)

常用指令特别讲解

●指令MOV作用:

1.完成寄存器与寄存器、寄存器与内存之间数据传递 2.完成标志位、密码表等的初始化 其中密码表一般为内存地址

标志位一般为寄存器,少量是内存地址

●关于堆栈的指令 1.压栈

ESP的值要减少 2.出栈

ESP的值要增加

跟踪堆栈的时候,不同的ESP格式的内存地址指向同一内存地址

建议尽量不要在内存地址是ESP格式的情况下锁定跟踪

●目的地址传送指令LEA 作用主要有两个 1.装载有效地址 指令示例:

mov eax, dword ptr [esi+XX] ; lea ebx, dword ptr [esi+XX] ; 经过跟踪发现[esi+XX]存放的是某字符串 那么EBX保存的是该字符串的地址

2.完成算术运算

lea eax, dword ptr [edi+XX] ; 等价于:EAX = EDI + XX;

●算术运算指令 求反:NEC

主要理解其用法:以 0 减之

往往和OR一起结合,完成对字符串长度的取值

乘法MUL MUL ECX

运算:EAX = EAX * ECX

除法DIV DIV ECX

运算:EAX = EAX / ECX EDX = EAX % ECX

●逻辑运算指令

\与\运算&

\或\运算^

\异或\运算|

以上三条指令常用作算法运算 做注册机时候分析起来比较头痛

\测试\

操作,进行异或运算 特点:

(1).不保存异或结果

(2).常和条件跳转指令结合在一起

测试一般有三个方向 1.对标志位值进行测试 格式如下

test EAX,EAX je/jne xxxxxxxx

2.对某位进行测试 test EAX,4

je/jne xxxxxxxx

对倒数第三位进行测试

3.进行奇偶测试 test EAX,80000001 je/jne xxxxxxxx

●移位指令 左移->乘 SHL EAX,2

等价于EAX = EAX * (2^2)

右移->除 SHR EAX,3

等价于EAX = EAX / (2^3)

三、定位程序注册代码段

1.试注册,判断保护方式 序列号(变相的序列号)

所谓变相的序列号就是程序没有输入注册码的地方,但会以文本文件方式通过读取特定的文件 如keyfile等

这类仍可以归类为序列号保护方式

2.查壳/脱壳 有壳脱之

无壳进行下一步

3.定位程序注册代码段

(1)超级字符串定位

A.有错误提示\

B.没有错误提示,但有正确提示\

C.[unregistered]

(2)通过API断点

A.有对话框

bp MessageBoxA(W)

B.没有对话框

bp GetWindowTextA(W) bp GetDlgItemTextA(W)

C.重启验证

bp RegCreateKeyA(W) bp RegDeleteKeyA(W) bp RegQueryValueA(W) bp RegCloseKey

bp RegOpenKeyA(W)

(3)其它

对付不同语言的工具选择

DEDE:确定delphi的按钮动作对应的代码

VB:SmartCheck

注意:必须是明码比较的VB程序

4.方法的选择 选择流程如下

字符串->对话框->文本->其它

调试还很依赖经验和运气,暂时无思路的程序可以先放放

有时候可以根据软件注册对话框样式猜出大致用什么思路定位,甚至可以猜到它的加密算法

5.AntiDbg

\高级话题\,暂时回避{偶暂时对这方面涉猎太少}o(n_n)o

1.在指令右侧注释栏填写必要的跟踪注释 应该着重注释的内容

(1).寄存器的值(数值/字符串)

(2).运算表达式

便于完成将来对算法的总结

(3).CALL功能

确定哪些CALL是关键CALL,哪些是无大意义的CALL 比如:

A.经过一个CALL后,字符串中的小写字母全部变为大写字母 这样的CALL,显然没有必要跟进去 B.又如

CALL XXXXXXXX TEST EAX,EAX

JE xxxxxxxx //跳向注册成功

这样的CALL一般来说是关键CALL(算法CALL) 很有必要跟进去探个究竟

(4).代码段的功能

确定代码段的功能,以便从全局的角度对整个注册流程进行分析

2.调试过程中,不同阶段,观察侧重点不同

A.首次调试

通常需要着重观察反汇编窗口和信息提示窗口

B.区段集中调试时期

应多注意寄存器和堆栈窗口

C.某条特殊指令 集中跟随数据窗口

3.一气呵成,又不拘泥

所谓一气呵成,就是指已经有了思路,那么就要一鼓作气,将其进行到底 不然,开工一半,中途搁置

过几天再拿起来...晕,又得从头分析

不拘泥

不是每个软件都是软柿子,不是每个软件设计者都不懂得ANTI-DBG 要知道,现在的程序员的软件保护意识越来越强的!!

暂时没有思路就先放一放,说生活中的某个细节会突然触发你的灵感

如果只是为了破解而破解,那么建议你放弃CRACKER这条路 学习破解只是一种很好的学习别人程序设计思路的方式 并在学习过程中体会到自身提高的乐趣

二、过程分析笔记

!!!阅读建议:

由于本篇是完全面向新手的文章,读者可以先下载注释笔记,然后浏览下 然后边调试边看以下分析内容,效果会更好 切记:一定要自己亲手调试

在本例中

我们用提示字符串进行注册代码段的定位

提示信息:\

向上看代码,一般是在程序段的段首下断点

关于\段首\的概念

可以这样理解:在向上代码段中出现第一个retn的下方

一般是push esp,push -1,push A,B格式的

本例中,我们在地址0045BDB0处F2下断

流程大致应该是这样的:

1.运行程序,输入试练码,程序被断下

2.进行首次跟踪

主要完成些重要数据的记录(旁白注释)

3.将程序细分段,确定各个分段的作用

4.进行细跟踪 搞定算法

实例讲解:

输入试练码: ID:luying10

SN:9876543210abcdef

点击确定,程序被OD断下

注意观察代码窗口、信息提示窗口、(寄存器窗口只要注意字符串类型数据就好)

并随时记录有用信息

;====================================================================|

0045BDB0 . 6A FF push -1 ; //0045BDB2 . 68 983A4700 push 00473A98 ; 0045BDB7 . 64:A1 0000000>mov eax, dword ptr fs:[0] 0045BDBD . 50 push eax

0045BDBE . 64:8925 00000>mov dword ptr fs:[0], esp 0045BDC5 . 51 push ecx 0045BDC6 . 53 push ebx 0045BDC7 . 56 push esi

0045BDC8 . 8BF1 mov esi, ecx 0045BDCA . 57 push edi

0045BDCB . 8D4C24 0C lea ecx, dword ptr [esp+C] 0045BDCF . E8 D4BE0000 call 0045BDD4 . 6A 01 push 1

0045BDD6 . 8BCE mov ecx, esi

断在这 0045BDD8 . C74424 1C 000>mov dword ptr [esp+1C], 0 0045BDE0 . E8 43C30000 call 0045BDE5 . E8 6CC20000 call

0045BDEA . 8B48 04 mov ecx, dword ptr [eax+4] 0045BDED . E8 78C30000 call ;

0045BDF2 . 68 E8030000 push 3E8 ; /Timeout = 1000. ms 0045BDF7 . FF15 3C524700 call dword ptr [<&KERNEL32.Sleep>] ; \\Sleep 0045BDFD . E8 54C20000 call

0045BE02 . 8B48 04 mov ecx, dword ptr [eax+4] 在经过地址0045BDF7的CALL时候,程序停顿了一小会儿

我们看英文注释也大概猜到这段代码的作用了----加入延时验证,防止暴力攻击 ;--------------------------------------------------------------------|

0045BE05 . E8 5AC30000 call ; 0045BE0A . 8B46 64 mov eax, dword ptr [esi+64] ; 0045BE0D . 8B4E 60 mov ecx, dword ptr [esi+60] ; 程序运行到0045BE0A这行时候

信息提示窗口提示dword ptr [esi+64] = \[esi+64]中保存的是序列号

这不正是我们最开始天的序列号嘛

运行本行代码后,发现EAX变成了序列号

同样,运行0045BE0D这行,ECX被赋予了用户名

;--------------------------------------------------------------------| 0045BE10 . 8D5E 64 lea ebx, dword ptr [esi+64] ; 0045BE13 . 8D7E 60 lea edi, dword ptr [esi+60] ; 这两行只有值,没有所谓的字符串的东东 我们学过LEA是装载有效地址的指令 [esi+64]中保存的是序列号

那么,执行完lea ebx, dword ptr [esi+64]后,EBX中保存的就应该是序列号的地址 同样,EDI中保存用户名的地址

;--------------------------------------------------------------------|

0045BE16 . 50 push eax ; 序列号压栈 0045BE17 . 51 push ecx ; 用户名压栈 压栈操作,不用多解释,下面是一个CALL,我们首次跟踪,先F8过

;--------------------------------------------------------------------- 0045BE18 . E8 83430000 call 004601A0 ; 0045BE1D . 83C4 08 add esp, 8 0045BE20 . 85C0 test eax, eax

0045BE22 . 75 1F jnz short 0045BE43 ; 运行了0045BE18这行的CALL后,EAX变为0

继续F8,来到跳转,跳转指向是绿色,跳转未实现

下面英文提示invalid username or registration code 显然再继续下去是提示注册失败咯

;--------------------------------------------------------------------| 0045BE24 . 6A 40 push 40

0045BE26 . 68 9C7C4900 push 00497C9C ; sorry

0045BE2B . 68 707C4900 push 00497C70 ; invalid username or registration code sorry

0045BE30 . 8BCE mov ecx, esi

0045BE32 . E8 EDC30000 call ; 提示注册失败,点击确定按钮,继续F8

;--------------------------------------------------------------------| 0045BE37 . C705 082C4E00>mov dword ptr [4E2C08], 0 ;

0045BE41 . EB 76 jmp short 0045BEB9 ; //程序跳走

;跳到这里来

0045BEB9 > 8BCE mov ecx, esi ; ->0045BEBB . E8 74C20000 call

0045BEC0 . 8D4C24 0C lea ecx, dword ptr [esp+C] 0045BEC4 . C74424 18 FFF>mov dword ptr [esp+18], -1 0045BECC . E8 8FBD0000 call

0045BED1 . 8B4C24 10 mov ecx, dword ptr [esp+10] 0045BED5 . 5F pop edi 0045BED6 . 5E pop esi 0045BED7 . 5B pop ebx

0045BED8 . 64:890D 00000>mov dword ptr fs:[0], ecx 0045BEDF . 83C4 10 add esp, 10

0045BEE2 . C3 retn ; //;====================================================================|

首轮跟踪结束,总结下:

1.关键跳转0045BE22

2.关键CALL->004601A0

3.标志位EAX

EAX = 0 注册失败 EAX = 1 注册成功

4.可疑处,地址:0045BE7 mov dword ptr [4E2C08], 0

两个研究方向

1.关键CALL->004601A0 2.可疑的赋值

跳走 来到这 结束

首先研究关键CALL

;====================================================================| ;在地址0045BE18处跟进关键CALL->004601A0

;--------------------------------------------------------------------| 004601A0 /$ 53 push ebx ; OD下方显示:本地调用来自 00428B46, 00429225, 0044BB64, 0045120C, 00455368, 0045BE18, 0045E824 004601A1 |. 55 push ebp

注意:从这里我们可疑看到,程序有多处代码调用了CALL=>004601A0

这也验证了为了程序只修改0014BE22处的关键跳转不能达到完全爆破的目的 ;--------------------------------------------------------------------| 004601A2 |. 8B6C24 0C mov ebp, dword ptr [esp+C] ; EBP = [esp+C] = 用户名

004601A6 |. 56 push esi 004601A7 |. 57 push edi

004601A8 |. BE 84014A00 mov esi, 004A0184 ; ESI = 4A0184 004601AD |. 8BC5 mov eax, ebp ; EAX = 004601AF |> 8A10 /mov dl, byte ptr [eax] ; 004601B1 |. 8A1E |mov bl, byte ptr [esi] 004601B3 |. 8ACA |mov cl, dl 004601B5 |. 3AD3 |cmp dl, bl

004601B7 |. 75 1E |jnz short 004601D7 ; 跳转实现//跳出循环体(跳至EAX置零) ;----------------------------

004601B9 |. 84C9 |test cl, cl

004601BB |. 74 16 |je short 004601D3 ; 004601BD |. 8A50 01 |mov dl, byte ptr [eax+1] 004601C0 |. 8A5E 01 |mov bl, byte ptr [esi+1] 004601C3 |. 8ACA |mov cl, dl 004601C5 |. 3AD3 |cmp dl, bl

004601C7 |. 75 0E |jnz short 004601D7 004601C9 |. 83C0 02 |add eax, 2 004601CC |. 83C6 02 |add esi, 2 004601CF |. 84C9 |test cl, cl

004601D1 |.^ 75 DC \\jnz short 004601AF ; //

004601D3 |> 33C0 xor eax, eax ; 004601D5 |. EB 05 jmp short 004601DC ; 程序跳出了循环体,条件是用户名不为空

我们可以看看如果程序从004601D5这跳会怎样

用户名

用户名的第1个字符 循环 首先跳至004601DC

因为EAX = 0,所以又跳至00460242 接着EAX置零后返回

而我们的主程序在EAX=0的时候是注册失败的

;----------------------------

004601D7 |> 1BC0 sbb eax, eax ; 004601D9 |. 83D8 FF sbb eax, -1 ; 004601DC |> 85C0 test eax, eax

004601DE |. 74 62 je short 00460242 ;

EAX=1,跳转未实现

综上,我们可疑得出,上段代码是检查用户名是否为空

;--------------------------------------------------------------------|

004601E0 |. 8B7C24 18 mov edi, dword ptr [esp+18] ; EDI = [esp+18] = 序列号

004601E4 |. BE 84014A00 mov esi, 004A0184 ; ESI = 4A0184 004601E9 |. 8BC7 mov eax, edi ;

004601EB |> 8A10 /mov dl, byte ptr [eax] ; 004601ED |. 8A1E |mov bl, byte ptr [esi] 004601EF |. 8ACA |mov cl, dl 004601F1 |. 3AD3 |cmp dl, bl

004601F3 |. 75 1E |jnz short 00460213 ; 跳转实现//跳出循环体(跳至EAX置零)

004601F5 |. 84C9 |test cl, cl

004601F7 |. 74 16 |je short 0046020F ; 004601F9 |. 8A50 01 |mov dl, byte ptr [eax+1] 004601FC |. 8A5E 01 |mov bl, byte ptr [esi+1] 004601FF |. 8ACA |mov cl, dl 00460201 |. 3AD3 |cmp dl, bl

00460203 |. 75 0E |jnz short 00460213 00460205 |. 83C0 02 |add eax, 2 00460208 |. 83C6 02 |add esi, 2 0046020B |. 84C9 |test cl, cl

0046020D |.^ 75 DC \\jnz short 004601EB ; //

0046020F |> 33C0 xor eax, eax ; 00460211 |. EB 05 jmp short 00460218 ; 程序跳出了循环体,条件是序列号不为空

我们可以看看如果程序从00460211这跳会怎样 首先跳至00460218

序列号的第i个字符循环 因为EAX = 0,所以又跳至00460242 接着EAX置零后返回

而我们的主程序在EAX=0的时候是注册失败的

00460213 |> 1BC0 sbb eax, eax ; 00460215 |. 83D8 FF sbb eax, -1 ; 00460218 |> 85C0 test eax, eax ; 0046021A |. 74 26 je short 00460242 ;

EAX=1,跳转未实现

综上,我们可疑得出,上段代码是检查序列号是否为空

;--------------------------------------------------------------------| 0046021C |. 57 push edi ; 0046021D |. 55 push ebp ; 0046021E |. E8 6DF9FFFF call 0045FB90 ; 00460223 |. 83C4 08 add esp, 8

00460226 |. 85C0 test eax, eax ; 00460228 |. 75 0E jnz short 00460238 ;

EDI保存序列号 EBP保存用户名 EAX = 0

跳转未实现,继续

有一个CALL->0045FB90 ,下次跟入

假设跳转实现,程序跳至00460238 EAX = 1,返回-》注册成功

;--------------------------------------------------------------------| 0046022A |. 57 push edi ; 0046022B |. 55 push ebp ; 0046022C |. E8 8FFBFFFF call 0045FDC0 ; 00460231 |. 83C4 08 add esp, 8

00460234 |. 85C0 test eax, eax ; 00460236 |. 74 0A je short 00460242 ;

EDI保存序列号 EBP保存用户名 EAX = 0 跳转实现

EAX = 0,返回,注册失败

假设跳转未实现

EAX = 1,返回,注册成功

;--------------------------------------------------------------------| 00460238 |> 5F pop edi 00460239 |. 5E pop esi 0046023A |. 5D pop ebp

0046023B |. B8 01000000 mov eax, 1 ; 00460240 |. 5B pop ebx

00460241 |. C3 retn ; 标志位赋值:EAX = 1 //返回

;--------------------------------------------------------------------| 00460242 |> 5F pop edi ; 跳转来自 004601DE, 0046021A, 00460236 00460243 |. 5E pop esi 00460244 |. 5D pop ebp

00460245 |. 33C0 xor eax, eax ; 00460247 |. 5B pop ebx

00460248 \\. C3 retn ; EAX置零//返回

;====================================================================|

跟进call 0045FB90 ,只有一处调用

跟进call 0045FDC0 ,只有一处调用

我们可以爆破了

在第二层中想办法让EAX的返回值为1

思路.

1.修改关键跳转

地址00460236处jnz改为jmp

2.修改赋值语句

地址00460245处xor eax,eax修改为inc eax(nop填充)

哈哈,这么简单就搞定``````

还有个可疑点呢,别忘了噢~~~

我们在运行到0045BE20 . 85C0 test eax, eax 这行时候,修改下EAX的值,将其由0置为1 使下面的跳转实现

;--------------------------------------------------------------------| 0045BE43 > 8B07 mov eax, dword ptr [edi] ; 0045BE45 . 8D4C24 0C lea ecx, dword ptr [esp+C]

0045BE49 . 50 push eax ;

0045BE4A . 68 547C4900 push 00497C54 ; license to:%s 0045BE4F . 51 push ecx

0045BE50 . E8 07C20000 call

0045BE55 . 8B5424 18 mov edx, dword ptr [esp+18] ; 提示窗口信息(ASCII \;---------------------------

0045BE59 . 83C4 0C add esp, 0C 0045BE5C . 8BCE mov ecx, esi 0045BE5E . 6A 40 push 40

0045BE60 . 68 487C4900 push 00497C48 ; thank you 0045BE65 . 52 push edx ; 提示窗口信息(ASCII \

0045BE66 . E8 B9C30000 call ;

提示注册成功

;---------------------------

0045BE6B . 57 push edi

0045BE6C . B9 04034A00 mov ecx, 004A0304 ; ASCII \0045BE71 . E8 3EBE0000 call 0045BE76 . 53 push ebx

0045BE77 . B9 08034A00 mov ecx, 004A0308 ; ASCII \0045BE7C . E8 33BE0000 call

0045BE81 . C705 082C4E00>mov dword ptr [4E2C08], 1 ; 这块很可疑噢~

mov dword ptr [4E2C08], 1 ;---------------------------

0045BE8B . 8B3F mov edi, dword ptr [edi] ; 0045BE8D . 57 push edi ;

0045BE8E . 68 A0F24800 push 0048F2A0 ; username 0045BE93 . 68 94F24800 push 0048F294 ; register 0045BE98 . B9 F4014A00 mov ecx, 004A01F4

0045BE9D . E8 5EC7FEFF call 00448600 ; EDI为用户名

0045BEA2 . 8B1B mov ebx, dword ptr [ebx] ; 0045BEA4 . B9 F4014A00 mov ecx, 004A01F4

0045BEA9 . 53 push ebx ;

萷?\乇?\

0045BEAA . 68 84F24800 push 0048F284 ; registercode 0045BEAF . 68 94F24800 push 0048F294 ; register 0045BEB4 . E8 47C7FEFF call 00448600 ; EBX为序列号

;---------------------------

0045BEB9 > 8BCE mov ecx, esi ; 0045BEBB . E8 74C20000 call

0045BEC0 . 8D4C24 0C lea ecx, dword ptr [esp+C] 0045BEC4 . C74424 18 FFF>mov dword ptr [esp+18], -1 0045BECC . E8 8FBD0000 call

0045BED1 . 8B4C24 10 mov ecx, dword ptr [esp+10] 0045BED5 . 5F pop edi 0045BED6 . 5E pop esi 0045BED7 . 5B pop ebx

0045BED8 . 64:890D 00000>mov dword ptr fs:[0], ecx 0045BEDF . 83C4 10 add esp, 10

0045BEE2 . C3 retn ; //结束

;====================================================================|

注册失败mov dword ptr [4E2C08], 0 注册成功mov dword ptr [4E2C08], 1

分析,将注册失败后[4E2C08]也赋值为1 但在整个程序中,有很多地方调用关键CALL 并且两段是不相干的代码

修改地址赋值不能改变关键CALL

修改关键CALL后该地址赋值就相应随之发生变化

结论:修改此处,不能达到完美爆破的目的

只修改关键CALL就可以达到完美爆破的目的

通过本文,主要是让兄弟们学会如何给程序加注释,和确定程序代码段的功能

两点说明:

1.恰当的书写注释

注释不是越多越好,太多的注释反而影响程序的阅读 用最少的文字表达概括语句含义

2.注册流程分析的意义

明确区段代码的作用,为以后定位注册关键代码段做铺垫,减少不必要的代码分析 程序实例仍旧是Media-WorkShop

前文回顾

先来看看我们在第二篇的部分代码分析

;---------------------------<载入注册计算方案(一)>-------------------|

0046021C |. 57 push edi ; 压栈(序列号) 0046021D |. 55 push ebp ; 压栈(用户名) 0046021E |. E8 6DF9FFFF call 0045FB90 ; |*|注册算法<一> 00460223 |. 83C4 08 add esp, 8

00460226 |. 85C0 test eax, eax ; 标志位测试

00460228 |. 75 0E jnz short 00460238 ; //;---------------------------<载入注册计算方案(二)>-------------------|

0046022A |. 57 push edi ; 0046022B |. 55 push ebp ; 0046022C |. E8 8FFBFFFF call 0045FDC0 ; |*|00460231 |. 83C4 08 add esp, 8

00460234 |. 85C0 test eax, eax ; 00460236 |. 74 0A je short 00460242 ; //;---------------------------<标志位赋值(注册成功EAX=1)>--------------| 00460238 |> 5F pop edi 00460239 |. 5E pop esi 0046023A |. 5D pop ebp

0046023B |. B8 01000000 mov eax, 1 ; 00460240 |. 5B pop ebx

00460241 |. C3 retn ; //;---------------------------<标志位赋值(注册失败EAX=0)>--------------|

00460242 |> 5F pop edi ; 0046021A, 00460236

00460243 |. 5E pop esi 00460244 |. 5D pop ebp

00460245 |. 33C0 xor eax, eax ; EAX00460247 |. 5B pop ebx

00460248 \\. C3 retn ; //;--------------------------------------------------------------------|

下面开始进行注册算法一的分析

;====================================================================| ;在地址0046021E处F7跟进注册算法CALL->0045FB90

;--------------------------------------------------------------------|

0045FB90 /$ 6A FF push -1 ; //0046021E

不跳则进入算法二压栈(序列号) 压栈(用户名) 注册算法<二> 标志位测试 跳则挂 标志位赋值:EAX = 1 返回 跳转来自 004601DE, 置零 返回 本地调用来自 0045FB92 |. 68 70414700 push 00474170 ; SE 处理程序安装 0045FB97 |. 64:A1 0000000>mov eax, dword ptr fs:[0] 0045FB9D |. 50 push eax

0045FB9E |. 64:8925 00000>mov dword ptr fs:[0], esp 0045FBA5 |. 83EC 14 sub esp, 14

0045FBA8 |. 8B4424 24 mov eax, dword ptr [esp+24] ; EAX = 用户名 0045FBAC |. 53 push ebx

0045FBAD |. 55 push ebp ; 用户名压栈 0045FBAE |. 56 push esi

0045FBAF |. 57 push edi ; 序列号压栈 0045FBB0 |. 50 push eax ; 用户名压栈 0045FBB1 |. 8D4C24 18 lea ecx, dword ptr [esp+18] 0045FBB5 |. E8 B8800000 call

0045FBBA |. 8D4C24 14 lea ecx, dword ptr [esp+14] ; ECX = 用户名的地址 0045FBBE |. C74424 2C 000>mov dword ptr [esp+2C], 0 0045FBC6 |. E8 E5840000 call

0045FBCB |. 8D4C24 14 lea ecx, dword ptr [esp+14] 0045FBCF |. E8 D6840000 call 0045FBD4 |. 6A 20 push 20

0045FBD6 |. 8D4C24 18 lea ecx, dword ptr [esp+18] 0045FBDA |. E8 71870000 call

0045FBDF |. 8B4C24 38 mov ecx, dword ptr [esp+38] ; ECX = 序列号 0045FBE3 |. 8BD8 mov ebx, eax ; EBX = 用户名 0045FBE5 |. 51 push ecx ; 序列号压栈 0045FBE6 |. 8D4C24 14 lea ecx, dword ptr [esp+14] 0045FBEA |. E8 83800000 call

0045FBEF |. 8D4C24 10 lea ecx, dword ptr [esp+10] 0045FBF3 |. C64424 2C 01 mov byte ptr [esp+2C], 1 0045FBF8 |. E8 B3840000 call

0045FBFD |. 8D4C24 10 lea ecx, dword ptr [esp+10] 0045FC01 |. E8 A4840000 call 0045FC06 |. 6A 20 push 20

0045FC08 |. 8D4C24 14 lea ecx, dword ptr [esp+14] 0045FC0C |. E8 3F870000 call

0045FC11 |. 8BD0 mov edx, eax ; EDX = 序列号 0045FC13 |. 83CE FF or esi, FFFFFFFF

0045FC16 |. 8BFA mov edi, edx ; EDI = 序列号 0045FC18 |. 8BCE mov ecx, esi

0045FC1A |. 33C0 xor eax, eax ; EAX置零 ;---------------------------<用户名长度不能大于序列号长度>---------------|

0045FC1C |. 895424 20 mov dword ptr [esp+20], edx ; [esp+20] = 序列号 0045FC20 |. F2:AE repne scas byte ptr es:[edi] 0045FC22 |. F7D1 not ecx

0045FC24 |. 49 dec ecx ; ECX = 序列号长度

0045FC25 |. 8BFB mov edi, ebx ; EDI = 用户名

0045FC27 |. 8BE9 mov ebp, ecx ; EBP = 用户名长度 0045FC29 |. 8BCE mov ecx, esi

0045FC2B |. F2:AE repne scas byte ptr es:[edi] 0045FC2D |. F7D1 not ecx

0045FC2F |. 49 dec ecx ; ECX = 用户名长度 0045FC30 |. 3BCD cmp ecx, ebp

0045FC32 |. 0F87 54010000 ja 0045FD8C ; //跳则挂(未实现) ;---------------------------<用户名不能为空>---------------------------|

0045FC38 |. 8BFB mov edi, ebx ; EDI = 用户名 0045FC3A |. 8BCE mov ecx, esi

0045FC3C |. F2:AE repne scas byte ptr es:[edi] 0045FC3E |. F7D1 not ecx

0045FC40 |. 49 dec ecx ; ECX = 用户名长度 0045FC41 |. 0F84 45010000 je 0045FD8C ; //跳则挂(未实现) ;---------------------------<序列号不能为空>---------------------------|

0045FC47 |. 8BFA mov edi, edx ; EDI = 序列号 0045FC49 |. 8BCE mov ecx, esi

0045FC4B |. F2:AE repne scas byte ptr es:[edi] 0045FC4D |. F7D1 not ecx

0045FC4F |. 49 dec ecx ; ECX = 序列号长度 0045FC50 |. 0F84 36010000 je 0045FD8C ; //跳则挂(未实现) ;---------------------------<注册运算验证>-----------------------------|

0045FC56 |. 894424 38 mov dword ptr [esp+38], eax ; [esp+38]初始化为0 ;------------------------------------[第一层开始]

0045FC5A |> 8B5424 38 /mov edx, dword ptr [esp+38] ; EDX = [esp+38] 0045FC5E |. 8D4C24 34 |lea ecx, dword ptr [esp+34] ; 加载序列号地址 0045FC62 |. 8A82 887E4900 |mov al, byte ptr [edx+497E88] ; 三次依次出现'P'/'W'/'M'

0045FC68 |. 884424 18 |mov byte ptr [esp+18], al ; [esp+18] = al 0045FC6C |. E8 37800000 |call

0045FC71 |. 8BFB |mov edi, ebx ; EDI = 用户名 0045FC73 |. 83C9 FF |or ecx, FFFFFFFF

0045FC76 |. 33C0 |xor eax, eax ; EAX置零 0045FC78 |. 33ED |xor ebp, ebp ; EBP置零 0045FC7A |. F2:AE |repne scas byte ptr es:[edi] 0045FC7C |. F7D1 |not ecx

0045FC7E |. 49 |dec ecx ; ECX = 用户名长度 0045FC7F |. C64424 2C 02 |mov byte ptr [esp+2C], 2 ; [esp+2C] = 2 0045FC84 |. 74 4B |je short 0045FCD1 ; //作用:跳过下面循环体

;---------------------------[第二层开始] [对用户名字符进行查表替换]

0045FC86 |> 8A042B |/mov al, byte ptr [ebx+ebp] ; 用户名的第i个字符

0045FC89 |. 33F6 ||xor esi, esi ; ESI置零

;---------[第三层开始] [对第i个字符进行查表替换]

0045FC8B |> 3A0475 207E49>||/cmp al, byte ptr [esi*2+497E20] ; 查表比较 0045FC92 |. 74 08 |||je short 0045FC9C ; //找到后,跳出本循环体

0045FC94 |. 46 |||inc esi ; ESI++ 0045FC95 |. 83FE 34 |||cmp esi, 34

0045FC98 |.^ 7C F1 ||\\jl short 0045FC8B ; //继续查找密码表中下一个字符

;---------[第三层结束]

0045FC9A |. EB 11 ||jmp short 0045FCAD ; //;---------<(I)找到了则跳到这>

0045FC9C |> 8A0C75 217E49>||mov cl, byte ptr [esi*2+497E21] ; 字母

0045FCA3 |. 51 ||push ecx

0045FCA4 |. 8D4C24 38 ||lea ecx, dword ptr [esp+38] 0045FCA8 |. E8 83820000 ||call ;---------<(II)没找到则跳到这>

0045FCAD |> 83FE 34 ||cmp esi, 34 ; 0045FCB0 |. 75 0E ||jnz short 0045FCC0 ; 处不跳

;---------<没有找到时进行的操作>

0045FCB2 |. 8B5424 18 ||mov edx, dword ptr [esp+18] ;

0045FCB6 |. 8D4C24 34 ||lea ecx, dword ptr [esp+34] ; 0045FCBA |. 52 ||push edx

0045FCBB |. E8 70820000 ||call ; 得字符串链接 ;---------|

0045FCC0 |> 8BFB ||mov edi, ebx ; EDI = 0045FCC2 |. 83C9 FF ||or ecx, FFFFFFFF

0045FCC5 |. 33C0 ||xor eax, eax ; EAX0045FCC7 |. 45 ||inc ebp

0045FCC8 |. F2:AE ||repne scas byte ptr es:[edi] 0045FCCA |. F7D1 ||not ecx

0045FCCC |. 49 ||dec ecx ; 0045FCCD |. 3BE9 ||cmp ebp, ecx

0045FCCF |.^ 72 B5 |\\jb short 0045FC86 ; //次

;---------------------------[第二层]

;---------<当运算所得字符串长度>=10H时,直接作为序列号>

0045FCD1 |> 8B4424 34 |mov eax, dword ptr [esp+34] ; (ASCII \0045FCD5 |. 8B48 F8 |mov ecx, dword ptr [eax-8] ; 0045FCD8 |. 83F9 10 |cmp ecx, 10

没找到,跳走 找到密码表中对应的和34比较 若上面没找到,则在此加载序列号地址 将替换字符和前面所用户名 置零 用户名长度 循环length(name)字符串的长度

0045FCDB |. 7D 3A |jge short 0045FD17 ; //大于等于10跳走 ;---------<当运算所得字符串长度<10H时,进行尾部补充>

0045FCDD |. 8BC1 |mov eax, ecx ; EAX = 长度 0045FCDF |. B9 10000000 |mov ecx, 10 ; ECX = 10H

0045FCE4 |. 2BC8 |sub ecx, eax ; ECX = ECX - EAX 0045FCE6 |. 8D5424 1C |lea edx, dword ptr [esp+1C] ; 加载补充字符串地址 0045FCEA |. 51 |push ecx ; 补充字符串长度压栈 0045FCEB |. 52 |push edx

0045FCEC |. B9 C02B4E00 |mov ecx, 004E2BC0

0045FCF1 |. E8 42800000 |call ; 0045FCF6 |. 50 |push eax

0045FCF7 |. 8D4C24 38 |lea ecx, dword ptr [esp+38] ; 符串地址

0045FCFB |. C64424 30 03 |mov byte ptr [esp+30], 3

0045FD00 |. E8 25820000 |call ; 0045FD05 |. 8D4C24 1C |lea ecx, dword ptr [esp+1C] 0045FD09 |. C64424 2C 02 |mov byte ptr [esp+2C], 2 0045FD0E |. E8 4D7F0000 |call

0045FD13 |. 8B4424 34 |mov eax, dword ptr [esp+34] ; (ASCII \

0045FD17 |> 8B4C24 20 |mov ecx, dword ptr [esp+20] ; 0045FD1B |. 51 |push ecx ; /s2 = 0045FD1C |. 50 |push eax ; |s1 = 0045FD1D |. FF15 A45A4700 |call dword ptr [<&MSVCRT._mbscmp>] ; \\(msvcrt._mbscmp)符串比较

0045FD23 |. 83C4 08 |add esp, 8

0045FD26 |. 8D4C24 34 |lea ecx, dword ptr [esp+34]

0045FD2A |. 85C0 |test eax, eax ; 0045FD2C |. C64424 2C 01 |mov byte ptr [esp+2C], 1 ; [esp+2C] = 1 0045FD31 |. 74 1B |je short 0045FD4E ; //0045FD33 |. 33F6 |xor esi, esi ; ESI0045FD35 |. E8 267F0000 |call

0045FD3A |. 8B4424 38 |mov eax, dword ptr [esp+38]

0045FD3E |. 40 |inc eax ; EAX++ 0045FD3F |. 83F8 03 |cmp eax, 3

0045FD42 |. 894424 38 |mov dword ptr [esp+38], eax ; [esp+38] = eax 0045FD46 |.^ 0F8C 0EFFFFFF \\jl 0045FC5A ; //;------------------------------------[第一层结束]

;---------<若从这跳则越过ESI=1,进而EAX=ESI=0,注册失败> 0045FD4C |. EB 0A jmp short 0045FD58

0045FD4E |> BE 01000000 mov esi, 1 ; ESI = 1 0045FD53 |. E8 087F0000 call

0045FD58 |> 8D4C24 10 lea ecx, dword ptr [esp+10] ; 0045FD5C |. C64424 2C 00 mov byte ptr [esp+2C], 0

确定补充字符串 加载上面运算所得字将两字符川进行链接 假码

真码 假码

字测试标志位 跳出循环体 置零 循环(三次) 加载假码地址 0045FD61 |. E8 FA7E0000 call

0045FD66 |. 8D4C24 14 lea ecx, dword ptr [esp+14] ; 加载用户名地址 0045FD6A |. C74424 2C FFF>mov dword ptr [esp+2C], -1 0045FD72 |. E8 E97E0000 call

0045FD77 |. 8BC6 mov eax, esi ; EAX = ESI 0045FD79 |. 5F pop edi 0045FD7A |. 5E pop esi 0045FD7B |. 5D pop ebp 0045FD7C |. 5B pop ebx

0045FD7D |. 8B4C24 14 mov ecx, dword ptr [esp+14] 0045FD81 |. 64:890D 00000>mov dword ptr fs:[0], ecx 0045FD88 |. 83C4 20 add esp, 20

0045FD8B |. C3 retn ; //返回(EAX=ESI) ;-------------<跳到下面就算玩完~~~>

0045FD8C |> 8D4C24 10 lea ecx, dword ptr [esp+10] ; 跳转来自 0045FC32, 0045FC41, 0045FC50

0045FD90 |. C64424 2C 00 mov byte ptr [esp+2C], 0 0045FD95 |. E8 C67E0000 call

0045FD9A |. 8D4C24 14 lea ecx, dword ptr [esp+14] 0045FD9E |. 897424 2C mov dword ptr [esp+2C], esi 0045FDA2 |. E8 B97E0000 call

0045FDA7 |. 8B4C24 24 mov ecx, dword ptr [esp+24] 0045FDAB |. 5F pop edi 0045FDAC |. 5E pop esi 0045FDAD |. 5D pop ebp

0045FDAE |. 33C0 xor eax, eax ; EAX置零 0045FDB0 |. 5B pop ebx

0045FDB1 |. 64:890D 00000>mov dword ptr fs:[0], ecx 0045FDB8 |. 83C4 20 add esp, 20

0045FDBB \\. C3 retn ; //返回(EAX=0) ;====================================================================|

在运行到0045FC8B时候,

0045FC62 |. 8A82 887E4900 |mov al, byte ptr [edx+497E88] 0045FC8B |> 3A0475 207E49>||/cmp al, byte ptr [esi*2+497E20] 跟随数据窗口,可以得到一张密码表换算表:

00497E20 61 43 62 78 63 69 64 49 65 41 66 58 67 4D 68 6B aCbxcidIeAfXgMhk 00497E30 69 45 6A 56 6B 5A 6C 65 6D 52 6E 79 6F 42 70 4B iEjVkZlemRnyoBpK 00497E40 71 64 72 54 73 53 74 50 75 57 76 6C 77 6A 78 44 qdrTsStPuWvlwjxD 00497E50 79 48 7A 46 41 7A 42 71 43 70 44 4F 45 6B 46 67 yHzFAzBqCpDOEkFg 00497E60 47 59 48 6D 49 74 4A 61 4B 72 4C 51 4D 6E 4E 73 GYHmItJaKrLQMnNs 00497E70 4F 75 50 55 51 47 52 4A 53 4C 54 4E 55 62 56 63 OuPUQGRJSLTNUbVc 00497E80 57 66 58 68 59 6F 5A 77 50 57 4D 00 25 30 32 64 WfXhYoZwPWM.d

00497E90 3A 25 30 32 64 3A 25 30 32 64 00 00 25 73 25 73 :d:d..%s%s 00497EA0 00 00 00 00 4C 64 51 73 42 63 6D 70 4A 70 61 45 ....LdQsBcmpJpaE 00497EB0 73 58 74 6F 00 00 00 00 25 30 38 6C 58 2D 25 30 sXto....lX-%0

换算关系如下:

a -> C b -> q c -> i d -> H e -> S f -> X g -> M h -> k i -> E j -> V k -> Z l -> e m -> R n -> y o -> B p -> K q -> d r -> T s -> A t -> F u -> W v -> l w -> j x -> D y -> I z -> P

A -> z B -> x C -> p D -> O E -> k F -> g G -> Y H -> m I -> t J -> a K -> r L -> Q M -> n N -> s O -> u P -> U Q -> G R -> J S -> L T -> N U -> b V -> c W -> f X -> h Y -> o Z -> w

非大小写类字母统一替换成P或W或M

注意,只能替换成同一个字母,不允许P、W、M交杂

用于补充作用的链接字符串为:LdQsBcmpJpaEsXto

算法总结:

1.先将用户名的各个字符进行替换 替换规则如下

(1).大小写字母进行查表

(2).非字母则统一替换为P或W或M 2.进行序列号长度校验

若长度小于10H,则用LdQsBcmpJpaEsXto进行补充,直至长度等于10H 若长度>=10H,则直接作为序列号

运算示例: ID:luying10

SN:eWHEyMPPLdQsBcmp eWHEyMWWLdQsBcmp eWHEyMMMLdQsBcmp

一个有趣的小问题

如果ID是中文的,因为不是英文字符,所以只能用P或W或M统一替换 所以,所有中文用户名对应的序列号只有三个

PPPPPPPPLdQsBcmp WWWWWWWWLdQsBcmp MMMMMMMMLdQsBcmp

好了,分析完注册算法一,借着兴致,一举拿下注册算法二

试练码: ID:luying10

SN:10000000-02000000-00300000-00040000-00005000-00000600-00000070-00000008 BTW:在地址0045FF2B 处lx...提示了我们序列号的格式 sn = s1-s2-s3-s4-s5-s6-s7-s8

;====================================================================| ;在地址0046022C处跟进注册算法(二)CALL->0045FDC0

;====================================================================|

0045FDC0 /$ 6A FF push -1 ; //本地调用来自 0046022C

0045FDC2 |. 68 D9414700 push 004741D9 ; SE 处理程序安装 0045FDC7 |. 64:A1 0000000>mov eax, dword ptr fs:[0] 0045FDCD |. 50 push eax

0045FDCE |. 64:8925 00000>mov dword ptr fs:[0], esp 0045FDD5 |. 81EC 94000000 sub esp, 94

0045FDDB |. 8B8424 A40000>mov eax, dword ptr [esp+A4] ; EAX = [esp+A4] = 用户名

0045FDE2 |. 53 push ebx 0045FDE3 |. 56 push esi

0045FDE4 |. 50 push eax ; 用户名压栈 0045FDE5 |. 8D4C24 10 lea ecx, dword ptr [esp+10]

0045FDE9 |. C74424 60 DF4>mov dword ptr [esp+60], C95841DF 0045FDF1 |. C74424 64 12E>mov dword ptr [esp+64], 717AE412 0045FDF9 |. C74424 68 ACE>mov dword ptr [esp+68], F015E3AC 0045FE01 |. C74424 6C B17>mov dword ptr [esp+6C], 1127EB1 0045FE09 |. C74424 70 895>mov dword ptr [esp+70], 1D455E89 0045FE11 |. C74424 74 51F>mov dword ptr [esp+74], 5375F151 0045FE19 |. C74424 78 6E4>mov dword ptr [esp+78], D34D4B6E 0045FE21 |. C74424 7C 81F>mov dword ptr [esp+7C], 88C5F181

n = 0x88C5F181D34D4B6E5375F1511D455E8901127EB1F015E3AC717AE412C95841DF

0045FE29 |. E8 447E0000 call

0045FE2E |. 8B8C24 B00000>mov ecx, dword ptr [esp+B0] ; ECX = [esp+B0] = 序列号

0045FE35 |. C78424 A40000>mov dword ptr [esp+A4], 0

0045FE40 |. 51 push ecx ; 序列号压栈 0045FE41 |. 8D4C24 0C lea ecx, dword ptr [esp+C] 0045FE45 |. E8 287E0000 call

0045FE4A |. 8B5424 0C mov edx, dword ptr [esp+C] ; EDX = [esp+0C] = 用户名

0045FE4E |. 8B35 A45A4700 mov esi, dword ptr [<&MSVCRT._mbscmp>; msvcrt._mbscmp

;---------------------------<检测用户名是否为空>---------------------|

0045FE54 |. 68 84014A00 push 004A0184 ; /s2 = \

0045FE59 |. 52 push edx ; |s1 = \用户名\0045FE5A |. C68424 AC0000>mov byte ptr [esp+AC], 1 ; |[esp+AC] = 1 0045FE62 |. FFD6 call esi ; \\_mbscmp 0045FE64 |. 83C4 08 add esp, 8 0045FE67 |. 85C0 test eax, eax

0045FE69 |. 0F84 0F020000 je 0046007E ; //跳则挂(未实现) ;---------------------------<检测序列号是否为空>---------------------|

0045FE6F |. 8B4424 08 mov eax, dword ptr [esp+8] ; EAX = [esp+8] = 列号

0045FE73 |. 68 84014A00 push 004A0184

0045FE78 |. 50 push eax ; 0045FE79 |. FFD6 call esi 0045FE7B |. 83C4 08 add esp, 8 0045FE7E |. 85C0 test eax, eax

0045FE80 |. 0F84 F8010000 je 0046007E ; //;--------------------------------------------------------------------|

0045FE86 |. 57 push edi ; 0045FE87 |. 6A 00 push 0 ; 0045FE89 |. 8D4C24 44 lea ecx, dword ptr [esp+44]

0045FE8D |. E8 EE3D0000 call 00463C80 ; 0045FE92 |. 6A 00 push 0

0045FE94 |. 8D4C24 4C lea ecx, dword ptr [esp+4C] 0045FE98 |. C68424 AC0000>mov byte ptr [esp+AC], 2

0045FEA0 |. E8 DB3D0000 call 00463C80 ; 0045FEA5 |. B3 03 mov bl, 3

0045FEA7 |. 68 01000100 push 10001 ; e 0045FEAC |. 8D4C24 5C lea ecx, dword ptr [esp+5C] 0045FEB0 |. 889C24 AC0000>mov byte ptr [esp+AC], bl

0045FEB7 |. E8 C43D0000 call 00463C80 ; 0045FEBC |. 8D4C24 58 lea ecx, dword ptr [esp+58] 0045FEC0 |. C68424 A80000>mov byte ptr [esp+A8], 4 0045FEC8 |. 51 push ecx

0045FEC9 |. 8D4C24 4C lea ecx, dword ptr [esp+4C] 0045FECD |. E8 0E3E0000 call 00463CE0

0045FED2 |. 8D4C24 58 lea ecx, dword ptr [esp+58] 0045FED6 |. 889C24 A80000>mov byte ptr [esp+A8], bl 0045FEDD |. E8 4E3E0000 call 00463D30

0045FEE2 |. 8D5424 60 lea edx, dword ptr [esp+60] 0045FEE6 |. 6A 08 push 8 0045FEE8 |. 52 push edx

0045FEE9 |. 8D4C24 48 lea ecx, dword ptr [esp+48] 0045FEED |. E8 5E3C0000 call 00463B50

序序列号压栈 跳则挂(未实现) 序列号压栈 = 10001H = 65537D

0045FEF2 |. B9 08000000 mov ecx, 8

0045FEF7 |. 33C0 xor eax, eax ; EAX置零 0045FEF9 |. 8D7C24 18 lea edi, dword ptr [esp+18] 0045FEFD |. 8D5424 2C lea edx, dword ptr [esp+2C] 0045FF01 |. F3:AB rep stos dword ptr es:[edi] 0045FF03 |. 8D4424 34 lea eax, dword ptr [esp+34] 0045FF07 |. 8D4C24 30 lea ecx, dword ptr [esp+30] 0045FF0B |. 50 push eax 0045FF0C |. 51 push ecx

0045FF0D |. 8D4424 30 lea eax, dword ptr [esp+30] 0045FF11 |. 52 push edx

0045FF12 |. 8D4C24 30 lea ecx, dword ptr [esp+30] 0045FF16 |. 50 push eax

0045FF17 |. 8D5424 30 lea edx, dword ptr [esp+30] 0045FF1B |. 51 push ecx

0045FF1C |. 8D4424 30 lea eax, dword ptr [esp+30] 0045FF20 |. 52 push edx

0045FF21 |. 8B5424 24 mov edx, dword ptr [esp+24] ; EDX = [esp+24] = 序列号

0045FF25 |. 8D4C24 30 lea ecx, dword ptr [esp+30]

;---------------------------<对假序列号进行变形运算>-----------------| 0045FF29 |. 50 push eax 0045FF2A |. 51 push ecx

0045FF2B |. 68 B87E4900 push 00497EB8 ; |lx-lx-lx-lx-lx-lx-lx-lx\\n

0045FF30 |. 52 push edx ; |s

0045FF31 |. FF15 405A4700 call dword ptr [<&MSVCRT.sscanf>] ; \\sscanf

0045FF37 |. 8B4424 50 mov eax, dword ptr [esp+50] ; s5 = 00005000 0045FF3B |. 8B4C24 4C mov ecx, dword ptr [esp+4C] ; s4 = 00040000 0045FF3F |. 8B7C24 48 mov edi, dword ptr [esp+48] ; s3 = 00300000 0045FF43 |. 8B5424 44 mov edx, dword ptr [esp+44] ; s2 = 02000000 0045FF47 |. 03C1 add eax, ecx ; s5 = s5 + s4 = 00045000

0045FF49 |. 8B4C24 5C mov ecx, dword ptr [esp+5C] ; s8 = 00000008 0045FF4D |. 03C7 add eax, edi ; s5 = s5 + s3 = 00345000

0045FF4F |. 8B7C24 58 mov edi, dword ptr [esp+58] ; s7 = 00000070 0045FF53 |. 03C2 add eax, edx ; s5 = s5 + s2 = 02345000

0045FF55 |. 8B5424 40 mov edx, dword ptr [esp+40] ; s1 = 10000000 (CDRIP.#299)

0045FF59 |. 33C8 xor ecx, eax ; s8 = s8 | s5 = 02345008

0045FF5B |. 8B4424 54 mov eax, dword ptr [esp+54] ; s6 = 00000600

0045FF5F |. 83C4 28 add esp, 28

0045FF62 |. 03C2 add eax, edx ; s6 = s6 + s1 = 10000600

0045FF64 |. 894C24 34 mov dword ptr [esp+34], ecx ; ecx=02345008 0045FF68 |. 33F8 xor edi, eax ; s7 = s7 | s6 = 10000670

;--------------------------------------------------------------------| 0045FF6A |. 6A 00 push 0

0045FF6C |. 8D4C24 3C lea ecx, dword ptr [esp+3C]

0045FF70 |. 897C24 34 mov dword ptr [esp+34], edi ; [esp+34] = edi = 10000670 (CDRIP.10000670)

0045FF74 |. E8 073D0000 call 00463C80

0045FF79 |. 8D4C24 18 lea ecx, dword ptr [esp+18] 0045FF7D |. 6A 08 push 8

0045FF7F |. 51 push ecx ; sn0045FF80 |. 8D4C24 40 lea ecx, dword ptr [esp+40] 0045FF84 |. C68424 B00000>mov byte ptr [esp+B0], 5

0045FF8C |. E8 BF3B0000 call 00463B50 ; rsa_de()SerNum^e mod n

0045FF91 |. 8D5424 38 lea edx, dword ptr [esp+38] 0045FF95 |. 8D4424 50 lea eax, dword ptr [esp+50] 0045FF99 |. 52 push edx 0045FF9A |. 50 push eax

0045FF9B |. 8D4C24 48 lea ecx, dword ptr [esp+48]

0045FF9F |. E8 0CC5FFFF call 0045C4B0 ; 0045FFA4 |. B9 08000000 mov ecx, 8 0045FFA9 |. 33C0 xor eax, eax

0045FFAB |. 8D7C24 18 lea edi, dword ptr [esp+18] 0045FFAF |. 6A 08 push 8

0045FFB1 |. F3:AB rep stos dword ptr es:[edi] 0045FFB3 |. 8D4C24 1C lea ecx, dword ptr [esp+1C] 0045FFB7 |. C68424 AC0000>mov byte ptr [esp+AC], 6 0045FFBF |. 51 push ecx

0045FFC0 |. 8D4C24 58 lea ecx, dword ptr [esp+58]

0045FFC4 |. E8 C73B0000 call 00463B90 ; 制字节串

0045FFC9 |. B9 08000000 mov ecx, 8

0045FFCE |. 33C0 xor eax, eax ; EAX0045FFD0 |. 8DBC24 800000>lea edi, dword ptr [esp+80]

0045FFD7 |. F3:AB rep stos dword ptr es:[edi] ;

0045FFD9 |. 5F pop edi ; ;-------------<交换每一个dword的高位,低位>

0045FFDA |> 8A5404 17 /mov dl, byte ptr [esp+eax+17] 0045FFDE |. 8A4C04 16 |mov cl, byte ptr [esp+eax+16]

变形后的SerNum ,计算 c = 结果以大数输出 c 大数结果转为十六进置零 序列号 0045FFE2 |. 885404 7C |mov byte ptr [esp+eax+7C], dl 0045FFE6 |. 8B5404 14 |mov edx, dword ptr [esp+eax+14] 0045FFEA |. 884C04 7D |mov byte ptr [esp+eax+7D], cl 0045FFEE |. 8A4C04 14 |mov cl, byte ptr [esp+eax+14] 0045FFF2 |. C1EA 08 |shr edx, 8

0045FFF5 |. 885404 7E |mov byte ptr [esp+eax+7E], dl 0045FFF9 |. 884C04 7F |mov byte ptr [esp+eax+7F], cl

0045FFFD |. 83C0 04 |add eax, 4 ; EAX = EAX + 4 00460000 |. 83F8 20 |cmp eax, 20

00460003 |.^ 7C D5 \\jl short 0045FFDA ; //

循环前:

0012EEF4 C4 3A 70 C1 5B DE 26 77 90 A1 42 3B E5 D8 0E 8A ?p循环(8次) 羀?w悺B;遑

0012EF04 40 B3 B2 FE 55 96 4A 1B EC B3 E0 78 D2 AE 42 6A @巢朖斐鄕耶Bj

循环后:

0012EF5C C1 70 3A C4 77 26 DE 5B 3B 42 A1 90 8A 0E D8 E5 羛:膚&轠;B?劐 0012EF6C FE B2 B3 40 1B 4A 96 55 78 E0 B3 EC 6A 42 AE D2 矦J朥x喑靔B

;--------------------------------------------------------------------|

00460005 |. 8D5424 7C lea edx, dword ptr [esp+7C] ; 加载转换后的地址 00460009 |. 8D4C24 10 lea ecx, dword ptr [esp+10] ; //0046000D |. 52 push edx

0046000E |. E8 5F7C0000 call

00460013 |. 8B4424 10 mov eax, dword ptr [esp+10] ; ss:[0012EEF0]=02449248

00460017 |. 8B4C24 0C mov ecx, dword ptr [esp+C] ; ss:[0012EEEC]=003FB228, (ASCII \

0046001B |. 50 push eax ; 0046001C |. 51 push ecx ; 0046001D |. FFD6 call esi ; 0046001F |. 83C4 08 add esp, 8

00460022 |. 8D4C24 10 lea ecx, dword ptr [esp+10] 00460026 |. 85C0 test eax, eax

00460028 |. C68424 A40000>mov byte ptr [esp+A4], 6

00460030 |. 0F84 86000000 je 004600BC ; //;--------------------------------------------------------------------| 00460036 |. E8 257C0000 call

0046003B |. 8D4C24 4C lea ecx, dword ptr [esp+4C] 0046003F |. C68424 A40000>mov byte ptr [esp+A4], 5 00460047 |. E8 E43C0000 call 00463D30

0046004C |. 8D4C24 34 lea ecx, dword ptr [esp+34] 00460050 |. 889C24 A40000>mov byte ptr [esp+A4], bl 00460057 |. E8 D43C0000 call 00463D30

0046005C |. 8D4C24 44 lea ecx, dword ptr [esp+44] 00460060 |. C68424 A40000>mov byte ptr [esp+A4], 8 00460068 |. E8 C33C0000 call 00463D30

0046006D |. 8D4C24 3C lea ecx, dword ptr [esp+3C] 00460071 |. C68424 A40000>mov byte ptr [esp+A4], 1 00460079 |. E8 B23C0000 call 00463D30

0046007E |> 8D4C24 08 lea ecx, dword ptr [esp+8] 00460082 |. C68424 A40000>mov byte ptr [esp+A4], 0 0046008A |. E8 D17B0000 call

0046008F |. 8D4C24 0C lea ecx, dword ptr [esp+C] 00460093 |. C78424 A40000>mov dword ptr [esp+A4], -1 0046009E |. E8 BD7B0000 call

固定字符串地址 堆栈 堆栈 转化后数值的地址 用户名 比较 关键跳 004600A3 |. 5E pop esi

004600A4 |. 33C0 xor eax, eax ; EAX置零 004600A6 |. 5B pop ebx

004600A7 |. 8B8C24 940000>mov ecx, dword ptr [esp+94] 004600AE |. 64:890D 00000>mov dword ptr fs:[0], ecx 004600B5 |. 81C4 A0000000 add esp, 0A0

004600BB |. C3 retn ; //返回(EAX=0) ;--------------------------------------------------------------------| 004600BC |> E8 9F7B0000 call

004600C1 |. 8D4C24 4C lea ecx, dword ptr [esp+4C] 004600C5 |. C68424 A40000>mov byte ptr [esp+A4], 5 004600CD |. E8 5E3C0000 call 00463D30

004600D2 |. 8D4C24 34 lea ecx, dword ptr [esp+34] 004600D6 |. 889C24 A40000>mov byte ptr [esp+A4], bl 004600DD |. E8 4E3C0000 call 00463D30

004600E2 |. 8D4C24 44 lea ecx, dword ptr [esp+44] 004600E6 |. C68424 A40000>mov byte ptr [esp+A4], 9 004600EE |. E8 3D3C0000 call 00463D30

004600F3 |. 8D4C24 3C lea ecx, dword ptr [esp+3C] 004600F7 |. C68424 A40000>mov byte ptr [esp+A4], 1 004600FF |. E8 2C3C0000 call 00463D30

00460104 |. 8D4C24 08 lea ecx, dword ptr [esp+8] 00460108 |. C68424 A40000>mov byte ptr [esp+A4], 0 00460110 |. E8 4B7B0000 call

00460115 |. 8D4C24 0C lea ecx, dword ptr [esp+C] 00460119 |. C78424 A40000>mov dword ptr [esp+A4], -1 00460124 |. E8 377B0000 call

00460129 |. 8B8C24 9C0000>mov ecx, dword ptr [esp+9C] 00460130 |. 5E pop esi

00460131 |. B8 01000000 mov eax, 1 ; EAX = 1 00460136 |. 5B pop ebx

00460137 |. 64:890D 00000>mov dword ptr fs:[0], ecx 0046013E |. 81C4 A0000000 add esp, 0A0

00460144 \\. C3 retn ; //;====================================================================|

算法总结:

1.对输入的假序列号进行变换 sn = s1-s2-s3-s4-s5-s6-s7-s8

s6' = s6 + s1

s7' = s7 | (s6 + s1)

s8' = s8 | (s2 + s3 + s4 + s5)

返回(EAX=1)

SerNum = s1-s2-s3-s4-s5-s6'-s7'-s8'

2.运算

c = SerNum ^ e mod n;

3.比较c和name

利用RSATool搞定RSA参数:

n = 88C5F181D34D4B6E5375F1511D455E8901127EB1F015E3AC717AE412C95841DF e = 10001

n = p * q

p:92D9586271DFD8D47C9AE783DED37E9F q:EE6F5C9077D0A54887558B9CA262B4C1

d:7AAB6636F5681EDE3D96CBAFDF9BE6F38A66563EB122E21AE8B94121DC164781

逆推:

1.将用户名每四个字符倒序排列,并且转成十六进制 2.进行ESA运算 3.计算SerNum

4.进行XOR运算,求得最终的serial number

ID:luying10

SN:8F2D4BBE-A742BFC7-0BBDF498-9E74023E-8AFCE799-AA97BDD7-1B8A741B-8980044D

通过文本,希望读者能够掌握两类比较典型的算法 1.查表类算法(密码表字符替换) 2.密码学算法(RSA)

关于算法分析推荐一篇文章:

《Ultra-$hare系列算法分析》

http://www.unpack.cn/viewthread.php?tid=19935

该实例特点: 1.非明码比较

2.运用密码学加密算法

3.有对字符和字符串的操作

4.一些隐含的东西(连字符,序列号头部特定字符等)

本篇是菜鸟学算法系列最后一篇,有些地方写的潦草,兄弟们多多担待~ 希望各位兄弟早日步入算法分析的大门```.o(n_n)o.

本文来源:https://www.bwwdw.com/article/2th5.html

Top