算法难度:⭐⭐
爆破难度:⭐
反调试:?
信息收集
运行情况:
虚拟机打开提示反调试
查壳与脱壳:
有壳,壳拖完了还是看不到导入函数名称,算了,直接带壳调试
调试分析
反调试?
没错,这里我就是要打一个问号,我还以为用了啥反调试,搞得我不知道是咋回事,程序就是跑不起来,最后发现,这tm就是硬编码的弹窗有调试器然后退出进程,把那个函数nop掉即可
首先是放在调试器里跑,不管壳,直接跑,跑到弹窗,然后点击暂停,找到弹窗函数调用的地方:
在网上追一层,找到最上面的函数头:是我们熟悉的窗口过程函数,这里是eax保存的是消息码
在cmp eax,133
这一行下断点,然后不断运行断下观察,在eax的值为多少之后程序弹窗,过程就不演示了,结果是eax=47时弹的窗
再次运行,从eax=47这个分支跟下去,单步跟踪,找到跑飞的地方:
程序在这里的int 2b
之后,立马就跑飞了,这里进入内核系统调用了,不知道返回到哪里了,这里在执行该指令之前,在内存布局视图中直接给代码段下断点,然后执行:
发现程序停在了刚刚会弹窗提示反调试的函数前面!!这个弹窗call的功能只有一个就是弹窗并退出进程
所以这里想要不弹窗正常启动软件,就需要把这个call给nop掉!然后跑起来就能进入程序界面了:
注册算法分析
直接就动态分析吧,这次
老样子,找窗口函数里控制码是111,参数为3eb的分支:
逻辑简单明了,获取UserId,获取Password,然后一个call,非0表示成功
跟进call看看,接下来就用IDA来分析:
首先是判断输入情况,UserId不能为空,Pasword长度为8位
接下来用UserId计算一个值,用Password计算一个值(atoi),然后异或一个固定值,最后进行比较
注册机
注册码生成算法:
#include <iostream>
int main()
{
char UserId[100] = { 0 };
std::cin >> UserId;
unsigned int check = 0x12345678;
for (size_t i = 0; i < strlen(UserId); i++)
check = ((check * 2) | (check >> 7)) ^ UserId[i];
check ^= 0xDDDDDDD0;
std::cout << std::hex << check;
}
效果: