双击运行,弹出对话框,猜测是MessageBox
点击确定,弹出主对话框
点击Serial/Name,提示输入用户名和序列号
随机输入,弹出提示对话框,提示序列号错误。猜测提示对话框是通过MessageBox调用。
通过首次运行中,推测点击Check it Baby!后弹出的对话框是通过MessageBox调用的,所以打开OD加载可执行文件,ALT+E 查看可执行模块。
找到主模块右键查看名称,即可查看到主模块中调用的函数。
搜索MessageBox,并在每个参考上设置断点。
Alt + b 查看所有断点。F9运行程序。
通过函数入参可以看出是首次运行时弹出的第一个对话框。按F9再次执行,首个对话框弹出。
点击Serial/Name,随机输入用户名和序列号,点击Check it Baby!,再次停在MessageBox断点处。通过函数入参,可以发现是检验用户名和序列号后弹出的对话框文本。
在栈中查看函数返回地址,返回调用函数,右键 --> 反汇编窗口中跟随
向上查看汇编指令,可以看到MessageBox的文本参数。jnz short 0042FB1F是关键跳,表示结果不相等则跳转到0042FB1F处。
将关键跳使用nop填充后运行,随机输入用户名和序列号,发现验证成功,该方法是爆破。
在上面几个call下断点,逐个分析,发现疑似序列号文本。
输入用户名和对应的序列号发现验证成功。
在栈中 EBP-4,EBP-8,EBP-18的数据,分别是序列号的三部分,通过反汇编窗口0x0042FAC5内存位置可以看出获取了EBP-18内存地址。在此处下断点重新运行。
单步调试可以发现,代码逻辑是先获取EBP-18的内存地址赋值到edx寄存器,然后取内存地址为0x00431750的四个字节内容赋值到eax寄存器。
单步步过0x0042FACD内存地址处call。查看栈EBP-18位置,序列号第二部分4018被赋值到EBP-18位置。也就是说内存地址为0x00431750的值0x0FB2经过了0x0042FACD内存地址处call计算得出4018。其实就是做了进制转换,将十六进制转换成了十进制。
那么就需要知道内存地址为0x00431750是什么时候得到此值的,看上面的汇编指令。在0x0042FA87内存地址处下断点,重新运行。可以发现0x00431750现在值为0x29
单步运行,将我们输入的用户名字符串地址赋值给寄存器eax,然后取用户名第一个字节(ASCII码)乘0x29,将结果乘2,最后 赋值回0x00431750
0x29是固定值,所以整体算法逻辑就是,0x00431750 = 取用户名第一个字节 * 0x29 * 2,将0x00431750取四个字节十六进制转换成十进制,就得到了序列号第二部分,最后拼接字符串CW-XXX-CRACKED。
刚刚接触逆向的小白,编程能力还有待提升,记录一下学习过程。欢迎大佬给予意见,感谢。目标程序已上传附件。
using namespace std;
int
main()
{
while
(true)
{
printf(
"请输入用户名:"
);
string szName;
cin >> szName;
if
(szName.size() <
4
)
{
printf(
"用户名长度小于4,请重新输入!\r\n"
);
continue
;
}
unsigned
int
nTmp
=
0x29
;
/
/
取第一个字节
unsigned
int
nFirst
=
szName[
0
];
unsigned
int
nSecondRes
=
nTmp
*
nFirst
*
2
;
char szSecond[
255
]
=
{};
itoa(nSecondRes, szSecond,
10
);
string szFirst
=
{
"CW-"
};
string szFinal
=
{
"-CRACKED"
};
string szSerialNumber;
szSerialNumber.append(szFirst).append(szSecond).append(szFinal);
printf(
"序列号为:%s\r\n"
, szSerialNumber.c_str());
}
return
0
;
}
using namespace std;
int
main()
{
while
(true)
{
printf(
"请输入用户名:"
);
string szName;
cin >> szName;
if
(szName.size() <
4
)
{
printf(
"用户名长度小于4,请重新输入!\r\n"
);
continue
;
}
unsigned
int
nTmp
=
0x29
;
/
/
取第一个字节
unsigned
int
nFirst
=
szName[
0
];
unsigned
int
nSecondRes
=
nTmp
*
nFirst
*
2
;
char szSecond[
255
]
=
{};
itoa(nSecondRes, szSecond,
10
);
string szFirst
=
{
"CW-"
};
string szFinal
=
{
"-CRACKED"
};
string szSerialNumber;
szSerialNumber.append(szFirst).append(szSecond).append(szFinal);
printf(
"序列号为:%s\r\n"
, szSerialNumber.c_str());
}
return
0
;
}
.
586
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
include kernel32.inc
include Resource.inc
include msvcrt.inc
includelib user32.lib
includelib kernel32.lib
includelib msvcrt.lib
WinMain proto :DWORD
.data
g_szUserName db
256
dup(
0
)
g_szErrorInfo db
"用户名个数小于4,请重新输入"
,
0
g_nBase dd
0
g_szFirst db
"CW-"
,
0
g_szFinal db
"-CRACKED"
,
0
g_szSecond db
256
dup (
0
)
g_szTmp db
"%d"
,
0
g_szResult db
256
dup (
0
)
.code
;对话过程函数
DlgProc proc hWnd:HWND,nMsg:UINT,wParam:WPARAM,lParam:LPARAM
.IF nMsg
=
=
WM_COMMAND
mov eax,wParam
.IF ax
=
=
IDB_GENERATE
;获取用户名编辑框中的文本
invoke GetDlgItemText,hWnd,IDE_NAME,offset g_szUserName,
255
.IF eax <
4
invoke MessageBox,NULL,offset g_szErrorInfo,NULL,MB_OK
mov eax,FALSE
ret
.ENDIF
;取用户名文本首字节
movzx eax,byte ptr [g_szUserName]
mov dword ptr [g_nBase],
29h
imul dword ptr [g_nBase]
mov dword ptr[g_nBase],eax
mov eax,dword ptr[g_nBase]
add dword ptr[g_nBase],eax
invoke crt_sprintf,offset g_szSecond,offset g_szTmp,dword ptr[g_nBase]
invoke crt_strcat,offset g_szResult,offset g_szFirst
invoke crt_strcat,offset g_szResult,offset g_szSecond
invoke crt_strcat,offset g_szResult,offset g_szFinal
;设置序列号
invoke SetDlgItemText,hWnd,IDE_SERIAL,offset g_szResult
;清空序列号
mov byte ptr [g_szResult],
0
.ELSEIF ax
=
=
IDB_CANCEL
invoke EndDialog,hWnd,
0
mov eax,FALSE
ret
.ENDIF
.ELSEIF nMsg
=
=
WM_CLOSE
invoke EndDialog,hWnd,
0
.ENDIF
mov eax,FALSE
ret
DlgProc endp
WinMain proc hInst:HINSTANCE
;创建模态对话框
invoke DialogBoxParam,hInst,IDD_DLG1,NULL,offset DlgProc,
0
ret
WinMain endp
;程序入口点
start:
invoke GetModuleHandle, NULL
invoke WinMain,eax
invoke ExitProcess,eax
end start
.
586
.model flat,stdcall
option casemap:none
include windows.inc
include user32.inc
include kernel32.inc
include Resource.inc
include msvcrt.inc
includelib user32.lib
includelib kernel32.lib
includelib msvcrt.lib
WinMain proto :DWORD
.data
g_szUserName db
256
dup(
0
)
g_szErrorInfo db
"用户名个数小于4,请重新输入"
,
0
g_nBase dd
0
g_szFirst db
"CW-"
,
0
g_szFinal db
"-CRACKED"
,
0
g_szSecond db
256
dup (
0
)
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2023-8-29 21:08
被_Format编辑
,原因: