0%

开始拿到本题我也一脸茫然,也没有游戏说明。于是就随便看了看,发现菜单上的三个选项都提示Nope doesn’t work yet!,即这三个功能都不能用,再看看这个题目的分类是Menu,我想,这题就是要我们让这三个选项能正常使用吧,就类似于Crackme041那题,要我们加代码。开始呢,我想到的就是在结尾处添加代码,用ollydbg搜索了一下,发现很多必要的Api函数没有导入进去,手动添加又太麻烦。而且要加三个功能,汇编代码量肯定很大。于是就想起了dll注入,这个技术,我也是现学现用。它的原理是通过某种手段,让程序加载我们的dll,dll中的DllMain函数就会自动执行,我们可以把一些代码放这个函数里。这种技术也应用于许多病毒程序中。

为什么dll注入后可以控制应用程序?

在Windows中,每个应用程序都是独立运行在自己的内存空间,有没有发现,我们用ollydbg打开exe,第一行指令的地址总是0x401000 ,程序A从这个地址开始执行,程序B也从这个地址开始执行,但是他们互不影响,即这些地址并不是物理地址,而是一个相对的地址。每个程序有独立的地址空间,自己空间里的线程可以随便操控自己的内存,那么,如果我们把自己的dll加载到程序的空间里去,这个dll就成了程序的一部分,可以操控这个程序的内存。

阅读全文 »

本题要求在不修改源程序的情况下要去除开始的那个对话框

我们使用了调试的方法控制程序的执行,大概hook也可以用这种原理实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//调试器原理大概就是这样了吧 
#include <windows.h>
#include <iostream>

using namespace std;

//断点地址
DWORD dwBreakPoint = 0x401000;
//新的执行地址
DWORD dwNewEip = 0x401013;

int main() {
cout << "请确保本注册机与程序在同一个目录下面!" << endl;
cout << "按任意键继续..." << endl;
//该结构用于指定新进程的主窗口特性
STARTUPINFO si = { 0} ;
//.应用程序必须将cb初始化为sizeof(STARTUPINFO)
si.cb = sizeof(STARTUPINFO);
//在创建进程时相关的数据结构之一,该结构返回有关新进程及其主线程的信息。
PROCESS_INFORMATION pi = { 0 };
//创建一个调试进程
CreateProcess("defiler.2.exe",NULL,NULL,NULL,FALSE,DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS,NULL,NULL,&si,&pi);
//调试信息结构体
DEBUG_EVENT dbg;
//每个线程内核对象都维护着一个CONTEXT结构,里面保存了线程运行的状态,
//该结构里有各种信息,寄存器这些的,我们可以修改里面的内容达到控制程序运行的目的。
CONTEXT ct;
//线程的Handle
HANDLE h;
//设置标记
ct.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
//开始调试
while (WaitForDebugEvent(&dbg,INFINITE)) {
if (dbg.dwThreadId != pi.dwThreadId) {
ContinueDebugEvent(dbg.dwProcessId,dbg.dwThreadId,DBG_CONTINUE);
cout << "跳过其他线程" << endl;
continue;
}
switch (dbg.dwDebugEventCode) {
case CREATE_PROCESS_DEBUG_EVENT://调试进程的创建
//获取线程的句柄
h = OpenThread(THREAD_ALL_ACCESS,FALSE,dbg.dwThreadId);
GetThreadContext(h,&ct);
ct.Dr0 = dwBreakPoint; //设置断点地址
ct.Dr7 = 0x101;
SetThreadContext(h,&ct);
CloseHandle(h);
ContinueDebugEvent(dbg.dwProcessId,dbg.dwThreadId,DBG_CONTINUE);
break;
case EXCEPTION_DEBUG_EVENT://接收到调试事件
//断点事件
if (0x4000001e == dbg.u.Exception.ExceptionRecord.ExceptionCode) {
cout << "捕捉到断点" << endl;
HANDLE h = OpenThread(THREAD_ALL_ACCESS,FALSE,dbg.dwThreadId);
DWORD dwPid = GetProcessId(pi.hProcess);
MessageBox(NULL,"这是注入的对话框!","hello",0x40);
GetThreadContext(h,&ct);
//修改相关寄存器,达到对程序的控制
ct.Rip = dwNewEip;
SetThreadContext(h,&ct);
CloseHandle(h);
}
ContinueDebugEvent(dbg.dwProcessId,dbg.dwThreadId,DBG_CONTINUE);
break;
case EXIT_PROCESS_DEBUG_EVENT://调试进程结束
ContinueDebugEvent(dbg.dwProcessId,dbg.dwThreadId,DBG_CONTINUE);
ExitProcess(0);
break;
default:
ContinueDebugEvent(dbg.dwProcessId,dbg.dwThreadId,DBG_CONTINUE);
break;
}
}
return 0;
}