文章标题 POWSERISO4.3 算法分析
软件名称 POWSERISO4.3
编写语言 VC++7.0,无壳
调试工具 OD,PEID
软件简介 一款不错的光盘软件
只是为兴趣
加载程序
在GetWindowTextA()下断
输入
用户名:123456
假注册码 : 12345-67891-23456-78912-34567
得到用户名和假注册码存放地址
查询字符串,可以看到 Please input the user name
在此下断,
/*0042F8DC*/ PUSH PowerISO.004DDFC0
/*0042F8E1*/ PUSH EAX
/*0042F8E2*/ CALL PowerISO.0047A8DA 验证注册码是否为空
/*0042F8E7*/ ADD ESP,8
/*0042F8EA*/ TEST EAX,EAX
/*0042F8EC*/ JNZ SHORT PowerISO.0042F939 不为空则跳到0042F939
/*0042F8EE*/ PUSH EAX
/*0042F8EF*/ PUSH 40
/*0042F8F1*/ PUSH PowerISO.004CAFB4 ASCII:Please input the user name
来到0042F939
还可看见一条检验用户名长度的子程序
接下来可看到很多
CALL PowerISO.0048CC32
仔细观察堆栈数据
输入的注册码有5个部分,把他们连接起来
得到字符串: 1234567891234567891234567 共25位
存放地址 00C6B3C8
紧接来到
/*0042FA0D*/ CALL PowerISO.004309B0 核心计算函数
如果输出是 eax=1则注册成功 进入此函数
来到第一个 CALL
004309BA |. E8 41660200 CALL PowerISO.00457020
CALL PowerISO.00430900 是一个关键CALL
进入发现对地址 0053057C ~0053058B 16位地址做了手脚
经几次调试
是把用户名填充到此地址,每一个用户名后用一个0填充
比如用户名是 123456
0053057C 31 32 33 34 35 36 00 31 32 33 34 35 36 00 31 32 123456.123456.12
0053058C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
此之后来到
004309DA |. E8 41660200 CALL PowerISO.00457020
也是一个关键CALL
进入此CALL
他先把ebp 处的堆栈清空
我的ebp = 0012EB84 然后来到一个循环,此时ebx 指向我们的假码,用[ESI+EBX]寻址假码
1234567891234567891234567
00457054 |> /8A041E /MOV AL,BYTE PTR DS:[ESI+EBX] 寻址假的注册码,保存到 AL
00457057 |. |3C 20 |CMP AL,20
00457059 |. |884424 14 |MOV BYTE PTR SS:[ESP+14],AL
0045705D |. |74 36 |JE SHORT PowerISO.00457095
0045705F |. |3C 2D |CMP AL,2D
00457061 |. |74 32 |JE SHORT PowerISO.00457095
AL= 20或2D就跳
00457063 |. |8B4424 14 |MOV EAX,DWORD PTR SS:[ESP+14]
00457067 |. |50 |PUSH EAX
00457068 |. |E8 43000000 |CALL PowerISO.004570B0
关键CALL计算假码的序号
0045706D |. |8B4C24 20 |MOV ECX,DWORD PTR SS:[ESP+20]
00457071 |. |884424 18 |MOV BYTE PTR SS:[ESP+18],AL
00457075 |. |51 |PUSH ECX
00457076 |. |55 |PUSH EBP
00457077 |. |E8 84FEFFFF |CALL PowerISO.00456F00
关键CALL 大数相乘
0045707C |. |83C4 0C |ADD ESP,0C
0045707F |. |85C0 |TEST EAX,EAX
00457081 |. |75 1E |JNZ SHORT PowerISO.004570A1
00457083 |. |8B5424 14 |MOV EDX,DWORD PTR SS:[ESP+14]
00457087 |. |52 |PUSH EDX
00457088 |. |55 |PUSH EBP
00457089 |. |E8 C2FEFFFF |CALL PowerISO.00456F50
关键CALL 大数相加
0045708E |. |83C4 08 |ADD ESP,8
00457091 |. |85C0 |TEST EAX,EAX
00457093 |. |75 0C |JNZ SHORT PowerISO.004570A1
00457095 |> |46 |INC ESI
00457096 |. |3BF7 |CMP ESI,EDI
00457098 |.^\7C BA \JL SHORT PowerISO.00457054 有3个关键CALL
其中
00457068 |. |E8 43000000 |CALL PowerISO.004570B0 关键CALL
进入
004570B0 /$ 8A4C24 04 MOV CL,BYTE PTR SS:[ESP+4]
004570B4 |. 33C0 XOR EAX,EAX
004570B6 |> 3888 0C894D00 /CMP BYTE PTR DS:[EAX+4D890C],>
004570BC |. 74 08 |JE SHORT PowerISO.004570C6
004570BE |. 40 |INC EAX
004570BF |. 83F8 22 |CMP EAX,22
004570C2 |.^ 72 F2 \JB SHORT PowerISO.004570B6
004570C4 |. 33C0 XOR EAX,EAX
004570C6 \> C3 RETN
查看数据地址 004D890C
004D890C 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46 47 123456789ABCDEFG
004D891C 48 49 4A 4B 4C 4D 4E 50 51 52 53 54 55 56 57 58 HIJKLMNPQRSTUVWX
004D892C 59 5A 00 00 YZ..
长度是0x22
原来是计算他所出现的位置
如果是H就返回0x13; 来到第二个关键CALL
00457077 |. |E8 84FEFFFF |CALL PowerISO.00456F00
进入发现一个循环
00456F15 |> /33C9 /XOR ECX,ECX
00456F17 |. |8A0C3E |MOV CL,BYTE PTR DS:[ESI+EDI]
00456F1A |. |0FAFCB |IMUL ECX,EBX
00456F1D |. |03C8 |ADD ECX,EAX
00456F1F |. |81F9 00010000 |CMP ECX,100
00456F25 |. |880C3E |MOV BYTE PTR DS:[ESI+EDI],CL
00456F28 |. |7C 10 |JL SHORT PowerISO.00456F3A
00456F2A |. |8BC1 |MOV EAX,ECX
00456F2C |. |99 |CDQ
00456F2D |. |81E2 FF000000 |AND EDX,0FF
00456F33 |. |03C2 |ADD EAX,EDX
00456F35 |. |C1F8 08 |SAR EAX,8
00456F38 |. |EB 02 |JMP SHORT PowerISO.00456F3C
00456F3A |> |33C0 |XOR EAX,EAX
00456F3C |> |46 |INC ESI
00456F3D |. |83FE 20 |CMP ESI,20
00456F40 |.^\7C D3 \JL SHORT PowerISO.00456F15
在这段循环 ebx 始终 = 0x22 , EDI指向 ebp = 0012EB84
先取EDI指向的第一位乘以0x22,大于0x100则进位
仔细分析,是一个大数(EDI所指向的地址)*小数(0x22) 第三个CALL
00457089 |. |E8 C2FEFFFF |CALL PowerISO.00456F50
进入以后仔细观察,程序是一个加法
总结这三个CALL,先取得一个索引值Index
然后与大数相乘相加
BigNumber = (BigNumber * 0x22)+Index
循环25次
经过变换 得到大数
0012EB84 98 6C 01 F3 7E E2 21 16 15 87 33 2D 7C 3E 22 00 榣 髜? ?-|>".
0012EB94 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 从这段代码出来以后,有一个
004309E5 |. E8 26FEFFFF CALL PowerISO.00430810
进入这个CALL
可以看到 他现将ESP+8的数据转换
0012EB24 31 32 33 34 35 36 00 31 32 33 34 35 36 00 31 32 123456.123456.12
0012EB34 98 6C 01 F3 7E E2 21 16 15 87 33 2D 7C 3E 22 00 榣 髜? ?-|>".
0012EB24 是先前的用户名
0012EB34 是计算出来的大数
然后来到
0043085B |. E8 60FFFFFF CALL PowerISO.004307C0
关键CALL
进入
004307D5 |> /33D2 /XOR EDX,EDX 计算,结果保存在ecx
004307D7 |. |8A30 |MOV DH,BYTE PTR DS:[EAX]
004307D9 |. |33CA |XOR ECX,EDX
004307DB |. |40 |INC EAX
004307DC |. |BA 08000000 |MOV EDX,8
004307E1 |> |F6C5 80 |/TEST CH,80
004307E4 |. |74 0A ||JE SHORT PowerISO.004307F0
004307E6 |. |03C9 ||ADD ECX,ECX
004307E8 |. |81F1 21100000 ||XOR ECX,1021
004307EE |. |EB 02 ||JMP SHORT PowerISO.004307F2
004307F0 |> |D1E1 ||SHL ECX,1
004307F2 |> |4A ||DEC EDX
004307F3 |.^|75 EC |\JNZ SHORT PowerISO.004307E1
004307F5 |. |4E |DEC ESI
004307F6 |.^\75 DD \JNZ SHORT PowerISO.004307D5
004307F8 |. 5E POP ESI
004307F9 |> 8AC1 MOV AL,CL ; cl和ch交换,存储于eax
004307FB |. 33D2 XOR EDX,EDX
004307FD |. 25 FF000000 AND EAX,0FF
00430802 |. 8AD5 MOV DL,CH
00430804 |. C1E0 08 SHL EAX,8
00430807 |. 03C2 ADD EAX,EDX
00430809 \. C3 RETN
还原C++代码
for(i = 0 ;i< 30; i++)
{
int a =Name[i];
a *= 256;
result ^= a;
for( j = 0 ;j < 8 ;j++)
{
if(result & 0x8000)
{
result *= 2;
result ^= 0x1021;
}
else
result *= 2;
}
}
//交换高16位和低16位
int a = result & 0x0FF;
int b = result & 0x0FF00;
result = a*256 + b/256;
这段代码不知如何求逆
此函数返回后
AX是返回值 = 1E96
返回后 和ESI+E处的值比较,也就是大数的最高位
我的是 0022 相等则注册成功 基本注册过程
1. 先填充用户名到16位
2. 由注册码计算大数BigNumber
伪码
For( i= 0 ; i<25 ;i++)
{
Int Index = GetIndex(Serial[i]);
BigNumber = BigNumber * 0x22 + Index;
}
3. 将大数加到用户名的后面,使其变成30位
4. 将变换后的用户名计算,得到一个值,与大数的最高位比较相等则注册成功
注册分析
无法直接用户名得到注册码,因为最后要把大数的前14位加入运算
可以先通过注册码来的到用户名,但求逆较困难
用间接法,
先输入用户名 123456
假注册码 1234567891234567891234567
得到 BigNumber :
0012EB84 98 6C 01 F3 7E E2 21 16 15 87 33 2D 7C 3E 22 00 榣 髜? ?-|>".
0012EB94 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
添加到用户名的后面
0012EB24 31 32 33 34 35 36 00 31 32 33 34 35 36 00 31 32 123456.123456.12
0012EB34 98 6C 01 F3 7E E2 21 16 15 87 33 2D 7C 3E| 22 00 榣 髜? ?-|>".
从3E处截止,通过第4部的计算
得到AX = 1E96 把大数的最高位0022变成1E96, 得到大数
98 6C 01 F3 7E E2 21 16 15 87 33 2D 7C 3E 96 1E
然后用这个大数反复相除0x22,取得余数,反求真的注册码,
伪码
ModTable[25];
i = 0;
While(BigNumber != 0)
{
BigNumber = BigNumber / 0x22;
ModTable[i] = BigNumber %0x22;
}
查找数组得到真注册码
可找出一个注册码
123456
84CBX-17JFH-VZDDR-T4BJB-YPJIN
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)