某网络播放器破解
大概去年的时候,我弟问我能不能破解这个软件,这个软件是他买修图课用的播放器,当时纯菜逼一个(虽然现在也垃圾), 一看加的vm,直接右键回收站。这几天心血来潮 跟他又要了这个播放器尝试破解,顺便要了他的账号和密码 然后开始分析首先用die查壳,vm壳 不过没有加反调试和反虚拟机 调试器能直接附加
随便输入账号密码 根据各种提示信息啥的定位到这个call,然后单步过去
可以看到ebp-0x3a8的栈返回了一个字符串地址
接下来输入别人正版账号密码看返回结果,发现是一个unicode格式的字符串 “AAAAAA424EA55F03-M9MM88974EA52FDMA9037802BB554A2M09433D|0||88900285g9mmy3|d966a02a4dd8b1244a0fd191bc8b273a”
然后我去拿这个字符串去patch错误的 在.data段随便找了一个空白区把数据复制过去 并且修改ebp-0x3a8的值,然后直接f9,然后返回了一个错误 好好好 果然没让我失望 破解失败
还得拿人家正版号去跟
然后继续看别人正版号的后续流程,在验证call之后 这个call又把ebp-8存的值改成了字符串地址,假码则不会 = 0,ok 那么我继续patch,修改 的值
修改之后继续f9 果然还是不行,继续跟正版号
这个call把返回的字符串大写变成小写,并且返回值是0x6a,继续看假码是怎么处理的
假码处理前 可以看到eax和edx是参数 eax是字符串 edx则是储存新字符串地址
处理后可以看到返回值差了很多 而且是0,紧接着跟了一条mov eax,xxxx的指令,当时没注意 直接又复制了一份小写的字符串以及修改ebp-8的值 还是挂了
挂了之后我去重新分析验证call 的下一个call 也就是call 0x42c13c
分析别人正版call 可以看到eax是字符串首地址 然后这里sub eax,4 然后mov eax, 可以发现这个值正好是0x6a,ok,那么我也去patch,将字符串前面四个字节改成6a,patch之后 这个call得到了和正版号一样的结果
,
可以看到ebp-8 这里已经不是0了
继续往下走可以看到效果和正版号一样 返回值0x6a,ebp-8也不是0,然后我又f9,然后直接抛了异常
由于之前拿别人正版号测试的时候也会抛异常 因为我把异常选项设置了不暂停 让被调试进程处理,走到这里我猜应该还有其他地方没有patch,联想之前的sub eax,4 ,我猜测前面的数据会不会也有用
重新执行 断到这里 字符串前面16个字节 然后除了之前的6a,我分别在另外三个字节下硬件断点
果然在这里 mov ecx,,对1进行了访问 edx是字符串地址,后续还有对这个值的修改 此处不在贴图 仅是为了证明这个值也要被用到
接下来是对第一个四字节的访问,可以看到mov edx,,注意此时这个四字节的值,是0x68d0010 接下来test dl,7 猜测这个值可能也有校验,我转到内存布局看到是申请的一个私有的页 而且基址是0x68d0000,大小是0x140000
然后我进行多次重新打开验证 发现mov edx,的值始终是申请的页基地址+0x10,猜测这个地址处可能有需要的值 也可能单纯验证地址,转到内存看一下,发现有值 ,把此处的值也复制过去,现在我们拿假码去尝试
把字符串依旧写在data段 看看结果如何
在验证call之后进行patch 然后f9 发现程序已经被破解了,很意外 当初还以为必须在那个申请的页面上,虽然说程序已经破解了 但是之前mov edx, test dl,7,猜测对这个只有一定的校验
把这个值改成b09700试一下,其他的值依旧patch了 直接f9 发现程序依然可以运行,具体原因已经懒得去研究了(狗头保命) 现在尝试patch
由于该程序没有重定位表 所以这里地址是死的,直接把数据找个空闲区扔过去 将这个call改掉,然后f9,程序可以正常运行 但是转储到文件再运行的时候发现弹框播放器损坏 有校验
vm壳带的校验 Ok啊 过不去 校验在vm里 没学过vm 水平不够 那只能通过动态修补了 直接写个程序去patch 直接让ai写 就直接WriteProcessMemory就好了
初次写这种破解 可能有点乱 逆向还得是敢于去猜 万一猜对了呢
代码如下:
#include <windows.h>
BOOL WriteProcessMemoryByPID(DWORD processID, LPVOID baseAddress, SIZE_T size, LPVOID buffer) {
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if (hProcess == NULL) {
MessageBoxA(0, "open process fail", 0, 0);
return FALSE;
}
SIZE_T bytesRead;
BOOL result = WriteProcessMemory(hProcess, baseAddress, buffer, size, &bytesRead);
if (!result || bytesRead != size) {
MessageBoxA(0, "patch failed", 0, 0);
CloseHandle(hProcess);
return result;
}
MessageBoxA(0, "patch success", 0, 0);
CloseHandle(hProcess);
return result;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CREATE: {
CreateWindowA("STATIC", "输入进程PID:", WS_VISIBLE | WS_CHILD, 20, 20, 120, 25, hwnd, NULL, NULL, NULL);
// 创建文本框
CreateWindowA("EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER, 150, 20, 100, 25, hwnd, (HMENU)1, NULL, NULL);
// 创建按钮
CreateWindowA("BUTTON", "patch", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 20, 60, 80, 25, hwnd, (HMENU)2, NULL, NULL);
break;
}
case WM_COMMAND:
if (LOWORD(wParam) == 3) {
DestroyWindow(hwnd);
}
if (LOWORD(wParam) == 2) { // 处理“patch”按钮点击
HWND editBox = GetDlgItem(hwnd, 1);
char text = {0};
SendMessageA(editBox, WM_GETTEXT, sizeof(text), (LPARAM)text);
int pid = atoi(text); // 将文本转换为整数
BYTE patchcode[] = {0xC7, 0x02, 0x10, 0xC8, 0xB2, 0x00, 0x90, 0x90 };
WriteProcessMemoryByPID(pid, (LPVOID)0x00AB385C, sizeof(patchcode), patchcode);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
char CLASS_NAME[] = "patch";
WNDCLASSA wc = { };
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClassA(&wc);
int width = 400;
int height = 200;
int x = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
int y = (GetSystemMetrics(SM_CYSCREEN) - height) / 2;
HWND hwnd = CreateWindowA(CLASS_NAME, 0, WS_OVERLAPPEDWINDOW, x, y, 300, 150, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nShowCmd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
zhiyuckt 发表于 2024-10-14 11:43
”发现mov edx,的值始终是申请的页基地址+0x10,猜测这个地址处可能有需要的值 也可能单纯验证地址, ...
这里的复制是将这个页基址+0x10的16个字节全部复制过去 是0x68,0x33,0xae,0x00以及后面的字节 也是纯猜的 这个我并没有去验证 可能有的字节没用到 为了保险复制了16个过去 ”发现mov edx,的值始终是申请的页基地址+0x10,猜测这个地址处可能有需要的值 也可能单纯验证地址,转到内存看一下,发现有值 ,把此处的值也复制过去”,这里的复制是指复制到AAAA字符串所在地址后面嘛?然后修改0x00AB385C处地址内容为0x10, 0xC8, 0xB2就可以爆破成功嘛?(该地址内是AAAA字符串和后面基地址+0x10的字符吗) 辛苦了,发个上来用用 学到了学到了
感谢分享还不错鼓励一下 太深奥了 没找到0x6a 真没看明白,还得加强学习。 深造播放器能搞定吗 厉害,我的兄弟{:1_921:}
厉害,我的兄弟{:1_893:}{:1_921:}