160个练手CrackMe-004

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 ebx
004281FD   .  56            push esi
004281FE   .  8BF2          mov esi,edx
00428200   .  8BD8          mov ebx,eax                               ; ebx <- eax 到这里猜想eax可能就没变化了。所以先试试。此时eax=0x02275028
00428202   .  8BD6          mov edx,esi
00428204   .  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,esp
00457C43  |.  51            push ecx
00457C44  |.  B9 05000000   mov ecx,0x5
00457C49  |>  6A 00         /push 0x0
00457C4B  |.  6A 00         |push 0x0
00457C4D  |.  49            |dec ecx
00457C4E  |.^ 75 F9         \jnz XCKme.00457C49
00457C50  |.  51            push ecx
00457C51  |.  874D FC       xchg [local.1],ecx
00457C54  |.  53            push ebx
00457C55  |.  56            push esi
00457C56  |.  8BD8          mov ebx,eax
00457C58  |.  33C0          xor eax,eax
00457C5A  |.  55            push ebp
00457C5B  |.  68 3D7E4500   push CKme.00457E3D
00457C60  |.  64:FF30       push dword ptr fs:[eax]
00457C63  |.  64:8920       mov dword ptr fs:[eax],esp
00457C66  |.  8BB3 F8020000 mov esi,dword ptr ds:[ebx+0x2F8]         ;  name的长度?
00457C6C  |.  83C6 05       add esi,0x5
00457C6F  |.  FFB3 10030000 push dword ptr ds:[ebx+0x310]
00457C75  |.  8D55 F8       lea edx,[local.2]
00457C78  |.  8BC6          mov eax,esi
00457C7A  |.  E8 85FEFAFF   call CKme.00407B04
00457C7F  |.  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                       ;  获取name
00457C96  |.  FF75 F4       push [local.3]                           ;  参数3:name
00457C99  |.  8D83 18030000 lea eax,dword ptr ds:[ebx+0x318]         ;  参数4:目标地址
00457C9F  |.  BA 04000000   mov edx,0x4                              ;  参数5:4
00457CA4  |.  E8 93BFFAFF   call CKme.00403C3C                       ;  连接字符串
00457CA9  |.  33D2          xor edx,edx
00457CAB  |.  8B83 F4020000 mov eax,dword ptr ds:[ebx+0x2F4]

这一段还不是太明白,只知道大致效果是这样。


写注册机:

name = input("Name:")
key = '黑头Sun Bird' + str(len(name)+5) + 'dseloffc-012-OK' + name
print('Key:', key, sep='')




DarkDe4.exe是DEDE 3.50.4的修改版(超强版:P) by DarkNess0ut 01.修改了Title和ClassName "DeDe"->"DarK",绝大部分的Anti检测都没有用了 02.DIY原DEDE,使得可以反汇编得到非标准程序的Forms格式和Procedures的事件(^_^) 03.直接反汇编功能的选项,原DEDE就提供了 "When this is checked DeDe will try to load the target and will read some valueable information from the new process memory that will be used later on. I do recommend this option to be ALWAYS checked! If it is not,DeDe will work little faster, but you will not have global var references, no unit inforamati on, DOI engine will work no more than 40% of its potential and many more *bad* things." Caption = 'Dump extra data and search for obj/prop references' 04.增加对特殊处理过的PACKAGEINFO的Uint List的显示,设定GetSectionIndexByRVA默认返回值是-1or2 选项在Option->configuration->Preferences->General-> Not Special Program And PACKAGEINFO,No Warn Saving 选择,将提供缺省功能; 不选,则增加对PACKAGEINFO的搜索功能和GetSectionIndexByRVA函数的默认返回值=2. (通常应该采用缺省模式,当反汇编有错误或PackageInfo有错时,尝试使用) 原有的"Do not allow report to be saved in existing folder"功能,继续保留,借鸡生蛋而已:) 使用原有english.ini的话, 选项将显示"Do not allow report to be saved in existing folder",请自行修改 05.修改原有的"Open With DEDE"的注册键错误&BUG,可以使用右键运行DEDE反汇编Delphi/BCB 06.去处NAG显示 07.修复原有Dump Active Process的BUG 可以 使用Shift+Alt+Ctrl+D Dump Process ->Dump.dmp文件 使用Shift+Alt+Ctrl+I Dump Info ->procinf_dmp.txt 08.Enable Dump按钮(画蛇添足:P) 09.修复拖放处理程序时,确认对话框的BUG! 10.修复Forms下将DFM保存为RES文件的BUG! 11.Enable Procedures下右键的Analize Class功能 12.修复Forms下DFM的"Open With NotePad"功能 13.heXer提供修复反汇编引擎的代码,修复后,爽歪歪啊:P 主要是解决了反汇编的错误
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值