exeinfo 查壳,没啥问题
打开 IDA,查找字符串
其中这一项比较可疑,形式一样,进入查看
进入,A
键整理字符串
整理好后是这样
X
键查看交叉引用
运气不错!进入
尝试 Tab
键转换成类 C 语言,因未定义函数,失败。
到起始位置,C
键转换成 code
,后 P
键转换成函数
这时就可以 Tab
键转换成类 C 语言,是函数 sub_40243A
this
类型明显不是 char**,应该是个句柄结构体指针,更换类型
IDA 帮我们分析好了,强强
观察这几部分,应该是个全局变量的数组
双击进入
换成数组
并 N
键重命名
ESC
键返回
Graph View
别扭,换成 Text View
,再在函数区域按 Tab
名字不对的话可以按 N
刷新
看着烦,隐藏了
发现里面没有加密函数,对 global_passwd
查看交叉引用,发现函数 sub_401F60
同样分析,先更换类型
函数 sub_401F60
关键代码如下,其中有生成 global_passwd
的关键部分
global_passwd
与程序开始运行时的时间、位置、计算机名称有关
GetLocalTime(&this->systemtime64);
v2 = this->systemtime64.wHour + this->systemtime64.wDay;
weekday = this->systemtime64.wDayOfWeek;
month = this->systemtime64.wMonth;
nSize = 256;
global_passwd[0] = this->systemtime64.wYear + month + weekday + 2 * v2;
GetComputerNameA(computerName, &nSize);
v5 = 0;
if (strlen(computerName))
{
v6 = global_passwd[1];
do
{
v7 = computerName[v5++];
v6 += this->systemtime64.wMonth + v7;
global_passwd[1] = v6;
} while (v5 < strlen(computerName));
}
GetModuleFileNameA(0, Filename, 0x100u);
for (i = 0; i < strlen(Filename); ++i)
global_passwd[2] = this->systemtime64.wHour * (global_passwd[1] + Filename[i]);
而对于比较难看懂的第四部分的验证,在于函数 sub_402340
中,其中有
(A= dword ptr -20h)
mov [esp+30h+A], 67452301h
mov [esp+30h+A+4], 0EFCDAB89h
mov [esp+30h+A+8], 98BADCFEh
mov [esp+30h+A+12], 10325476h
经搜索得 67452301h,0EFCDAB89h,98BADCFEh,10325476h
均为 MD5 中使用的函数,经进一步分析,得出函数行为就是 MD5!
最终,验证码的主体逻辑代码如下,其中
CWnd::UpdateData(1); // 刷新输入数据
strcpy(passwd, this->pchar7C); // 复制到String
passwd[19] = 0; // 末尾置'0'
v6 = global_passwd[0];
passwd[4] = 0; // 删除第一个'-'
passwd[9] = 0; // 删除第二个'-'
passwd[14] = 0; // 删除第三个'-'
passwd_1 = strtol(passwd, &EndPtr, 16); // 第一部分转成数值
passwd_2 = strtol(&passwd[5], &EndPtr, 16); // 第二部分转成数值
passwd_3 = strtol(&passwd[10], &EndPtr, 16); // 第三部分转成数值
strtol(&passwd[15], &EndPtr, 16);
a1[0] = passwd[15];
a1[1] = 0;
md5(a1, strlen(a1), v8);
if ( passwd_1 == v6
&& (CWnd::MessageBoxA(this, "恭喜你!序列号第1部分正确!", 0, 0), passwd_2 == (global_passwd[1] >> 8))
&& (CWnd::MessageBoxA(this, "恭喜你!序列号第2部分正确!", 0, 0), passwd_3 == ((global_passwd[0] + global_passwd[2]) >> 8))
&& (CWnd::MessageBoxA(this, "恭喜你!序列号第3部分正确!", 0, 0), v8[3] == 0x69772661)
&& passwd[16] == 'F'
&& passwd[17] == 'F'
&& passwd[18] == '0' )
{
result = CWnd::MessageBoxA(this, "恭喜你!序列号完全正确!", 0, 0);
}
分析得 python
脚本
import hashlib
import datetime
import socket
import os
time = datetime.datetime.now() # 获取当前时间
year = time.year
month = time.month
weekday = time.weekday() + 1 # 星期一应该对应'1',故加一
hour = time.hour
day = time.day
passwd = [0, 0, 0, 0]
passwd[0] = year + month + weekday + 2 * (hour + day)
computerName = socket.gethostname().upper() # 获取计算机名,需要大写
for ch in computerName:
passwd[1] += month + ord(ch)
fileFlag = False
filePath = ''
for root, dirs, files in os.walk(os.getcwd(), topdown=True):
if 'DemoD2022.exe' in files:
filePath = root + '\\DemoD2022.exe'
fileFlag = True
break
if fileFlag == False:
print('未找到 DemoD2022.exe ,请放至同一文件夹下')
exit(0)
for ch in filePath:
passwd[2] = hour * (passwd[1] + ord(ch))
for i in range(255):
m = hashlib.md5()
m.update(i.to_bytes(1, 'big'))
if m.hexdigest()[24:] == '69772661':
print(
('{:04X}-{:04X}-{:04X}-{}FF0').format(passwd[0], passwd[1] >> 8,
(passwd[0] + passwd[2]) >> 8,
chr(i)))