160个练手CrackMe-004
来源:互联网 发布:excel数据有效性日期 编辑:程序博客网 时间:2024/06/05 00:15
1、准备工作
无壳,Delphi编写,工具:DarkDe4(Delphi反汇编工具,定位事件地址)
2、OD载入运行,搜索字符串。
双击定位
0045803B为关键跳转。
[esi+0x30C] == 0x85 才提示注册成功,向上查看哪个地方有赋值操作。
在Panel1DbClick函数中发现赋值操作。
00457EFE |. C786 0C030000>mov dword ptr ds:[esi+0x30C],0x85
而给[esi+0x30C]赋值的条件是[esi+0x30C] == 0x3E,继续查看哪个地方写入了0x3E。
编辑框的chkcode函数中发现赋值操作。
而赋值条件是Call CKme.00403C。
到此知道了整个注册流程:
a.输入正确的Key
b.单击图片框
c.双击图片框,会显示图片,提示注册成功
单步运行到00457D35时,数据窗口中跟随edx就可以看到正确的Key了:“黑头Sun Brird8dseloffc-012-OK123”
此时可以分析内存关系,可以写内存注册机了。
3、内存注册机
从[ebx + 0x318]开始,向上层函数查。
00457C56 |. 8BD8 mov ebx,eax ; ebx的值由eax得来,eax是上层函数传的参数
00428185 . 8B83 C4010000 mov eax,dword ptr ds:[ebx+0x1C4] ; eax <- [ebx+0x1C4]
00428181 . 8BD8 mov ebx,eax ; ebx <- eax
此处省略几步。。。
004281FC . 53 push ebx004281FD . 56 push esi004281FE . 8BF2 mov esi,edx00428200 . 8BD8 mov ebx,eax ; ebx <- eax 到这里猜想eax可能就没变化了。所以先试试。此时eax=0x0227502800428202 . 8BD6 mov edx,esi00428204 . 8BC3 mov eax,ebx ; 这一层相关的是eax, eax <- ebx, 再往上看姑且把eax的值当做基值。
内存注册机:
#include <iostream>#include <windows.h>using namespace std;int main(){ int pid; int Base_adr = 0x02275028; //基值 int Key_adr; int tmp_adr; char key[50] = {0}; int num = 0; unsigned char tmp; printf("PID:"); scanf("%d", &pid); HANDLE hProcess = OpenProcess(2035711, false, pid); if(hProcess == NULL) cout << "Error!" << endl; else{ ReadProcessMemory(hProcess, (LPCVOID)(Base_adr+0x1C4), &tmp_adr, 4, NULL); //第一层关系 ReadProcessMemory(hProcess, (LPCVOID)(tmp_adr+0x318), &Key_adr, 4, NULL); //正确的Key的地址 ReadProcessMemory(hProcess, (LPCVOID)Key_adr, &tmp, 1, NULL); while(tmp != 0 && num < 50){ //循环取值,取到0表示结束 key[num++] = tmp; ReadProcessMemory(hProcess, (LPCVOID)Key_adr+num, &tmp, 1, NULL); } }// printf("%X\n", Key_adr); printf("%s\n", key); //当前name正确的key return 0;}
输入正确的Key后,单击双击操作后显示图片。
但这个内存注册机只对分析出基值的程序有效,上面所谓的基值新开一个程序就变了。好像和下面这个模块有关。
如果这个地址显示为02230000,则上面代码中基值应该是0x02235028。 022C0000则基值为0x022C5028 。暂时不知道解决办法。有机会再解决。
补:
查了一波资料,可以吧内存注册机当做一个小的调试器,以Debug方式创建进程,在Key漏出来的地方下断点,然后读取相关寄存器的值。
源码:
#include <iostream>#include <windows.h>using namespace std;int main() { char exePath[100] = {"C:\\CKme.exe"}; int int3_adr = 0x00457D35; // 设置断点的地方 unsigned char CC = 0xCC; unsigned char E8 = 0xE8; STARTUPINFO si; PROCESS_INFORMATION pi; DEBUG_EVENT devent; CONTEXT context; char key[50] = {0}; char tmp = 0; int num = 0;// LPCONTEXT lpContext; ZeroMemory( &si, sizeof(si)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESHOWWINDOW;// si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.wShowWindow = SW_SHOW; ZeroMemory( &pi, sizeof(pi) );// cout << "File Path:";// scanf("%s", exePath); if(CreateProcess(exePath, NULL, NULL, NULL, FALSE, DEBUG_PROCESS, NULL, NULL, &si, &pi)){// 以Debug方式创建进程 cout << "OK" << endl; while(TRUE){ if(WaitForDebugEvent(&devent, INFINITE)){//等待Debug事件 // cout << "Lai MI" << endl; switch(devent.dwDebugEventCode){// 过滤事件 case CREATE_PROCESS_DEBUG_EVENT:// cout << pi.dwProcessId << endl; WriteProcessMemory(pi.hProcess, (LPVOID)int3_adr, &CC, 1, NULL);//进程被创建时下断点 break; case EXCEPTION_DEBUG_EVENT:// SuspendThread(pi.hThread);if(devent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT){// 判断异常信息(int 3 断点信息为0x80000003) SuspendThread(pi.hThread);// 暂停线程 context.ContextFlags = CONTEXT_CONTROL;// 此Flags表示get或set Eip,Ebp...等寄存器 if(GetThreadContext(pi.hThread, &context)){ cout << "Eip:" << hex << context.Eip << endl; if(context.Eip != int3_adr + 1){// 判断异常的地方是否是我们想要的地方 // cout << hex << devent.u.Exception.ExceptionRecord.ExceptionCode << endl; ResumeThread(pi.hThread);// 其他地方的断点直接恢复线程 }else{context.ContextFlags = CONTEXT_INTEGER;// 此Flags表示get或set Eax,Ebx...等寄存器 if(GetThreadContext(pi.hThread, &context)){// 这里我们要get Edx的值,Edx指向了注册码 cout << "Edx:" << hex << context.Edx << endl;ReadProcessMemory(pi.hProcess, (LPCVOID)context.Edx, &tmp, 1, NULL);while(tmp != 0 && num < 50){key[num++] = tmp;ReadProcessMemory(pi.hProcess, (LPCVOID)(context.Edx+num), &tmp, 1, NULL);}cout << "This is the registration code:"; cout << key << endl;//输出注册码 }WriteProcessMemory(pi.hProcess, (LPVOID)int3_adr, &E8, 1, NULL);// 还原断点 context.ContextFlags = CONTEXT_CONTROL;context.Eip -= 1;SetThreadContext(pi.hThread, &context);// 还原 Eip ResumeThread(pi.hThread);// 恢复线程 } } } break; } ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId, DBG_CONTINUE);// 继续Debug事件 }else{ cout << "Error"; cout << GetLastError(); return 0; } } }else{ cout << "Error"; cout << GetLastError(); } return 0;}
效果图:程序运行起来后先随便几个字符。
4、追码
00457C40 /. 55 push ebp ; chkcode 真正判断函数00457C41 |. 8BEC mov ebp,esp00457C43 |. 51 push ecx00457C44 |. B9 05000000 mov ecx,0x500457C49 |> 6A 00 /push 0x000457C4B |. 6A 00 |push 0x000457C4D |. 49 |dec ecx00457C4E |.^ 75 F9 \jnz XCKme.00457C4900457C50 |. 51 push ecx00457C51 |. 874D FC xchg [local.1],ecx00457C54 |. 53 push ebx00457C55 |. 56 push esi00457C56 |. 8BD8 mov ebx,eax00457C58 |. 33C0 xor eax,eax00457C5A |. 55 push ebp00457C5B |. 68 3D7E4500 push CKme.00457E3D00457C60 |. 64:FF30 push dword ptr fs:[eax]00457C63 |. 64:8920 mov dword ptr fs:[eax],esp00457C66 |. 8BB3 F8020000 mov esi,dword ptr ds:[ebx+0x2F8] ; name的长度?00457C6C |. 83C6 05 add esi,0x500457C6F |. FFB3 10030000 push dword ptr ds:[ebx+0x310]00457C75 |. 8D55 F8 lea edx,[local.2]00457C78 |. 8BC6 mov eax,esi00457C7A |. E8 85FEFAFF call CKme.00407B0400457C7F |. FF75 F8 push [local.2] ; 参数1:str(len(name)+5)00457C82 |. FFB3 14030000 push dword ptr ds:[ebx+0x314] ; 参数2:'dseloffc-012-OK'00457C88 |. 8D55 F4 lea edx,[local.3]00457C8B |. 8B83 D4020000 mov eax,dword ptr ds:[ebx+0x2D4]00457C91 |. E8 B2B6FCFF call CKme.00423348 ; 获取name00457C96 |. FF75 F4 push [local.3] ; 参数3:name00457C99 |. 8D83 18030000 lea eax,dword ptr ds:[ebx+0x318] ; 参数4:目标地址00457C9F |. BA 04000000 mov edx,0x4 ; 参数5:400457CA4 |. E8 93BFFAFF call CKme.00403C3C ; 连接字符串00457CA9 |. 33D2 xor edx,edx00457CAB |. 8B83 F4020000 mov eax,dword ptr ds:[ebx+0x2F4]
这一段还不是太明白,只知道大致效果是这样。
写注册机:
name = input("Name:")key = '黑头Sun Bird' + str(len(name)+5) + 'dseloffc-012-OK' + nameprint('Key:', key, sep='')
阅读全文
0 0
- 160个练手CrackMe-004
- 160个练手CrackMe-001
- 160个练手CrackMe-002
- 160个练手CrackMe-003
- 160个练手CrackMe-005
- 160个练手CrackMe-006
- 160个练手CrackMe-007
- 160个练手CrackMe-008
- 160个练手CrackMe-009
- 160个练手CrackMe-010
- 160个练手CrackMe-011
- 160个练手CrackMe-012
- 160个练手CrackMe-013
- 160个练手CrackMe-014
- 160个练手CrackMe-015
- 160个练手CrackMe-016
- 160个练手CrackMe-017
- 160个练手CrackMe-018
- HYSBZ1941-Hide and Seek
- shell脚本语法
- 先码一个,try catch没有捕获到OutOFBoundsException
- DBSDFZOJ 模拟考试 命运 最小生成树+乱搞
- bat命令入门与高级技巧详解
- 160个练手CrackMe-004
- master -> master (non-fast-forward)和git ! [rejected] master -> master (fetch first)
- 前端之路——第七篇:整理目前疑问点/css必会伪类选择器/css媒体查询
- PAT 1025. 反转链表 (25)
- HDU
- MySQL 元数据
- Java上传文件到FTP服务器
- 如何部署Tomcat以及如何在任意目录下启动Tomcat
- ES6(七: 函数扩展)(name,箭头,函数绑定,尾调用优化)