0%

C-05_内存补丁、断点中断、单步中断

读取内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <Windows.h>
#include <TlHelp32.h>
char* p = 0x00D02030;
unsigned char code = 0;
void main() {

STARTUPINFO info = { sizeof(info) };
GetStartupInfo(&info);
PROCESS_INFORMATION pinfo;

TCHAR szPath[] = TEXT("C:\\Users\\test\\Desktop\\AsmDEMO.exe");
//CreateProcess(szPath, NULL, NULL, NULL, NULL, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &info, &pinfo);
//第六个参数可以改为null 读取不需要一定的权限
CreateProcess(szPath, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &info, &pinfo);
while (1) {
ReadProcessMemory(pinfo.hProcess, p, &code, 1, NULL);
printf("地址:%p 数值%02x\n", p, code);
Sleep(10);
((char*)p)++;
}

}
img

内存补丁

先生成一个asmdemo

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
;使用nmake或下列命令进行编译和链接
;ml /c /coff HelloWorld.asm
;Link /subsystem:windows HelloWorld.obj
;*******************************************************
;模式定义,初始化参数
.386 ;使用80386处理器指令集
.model flat,stdcall ;用来定义程序工作的模式,flat:内存模式,stdcall:语言模式
option casemap:none ;是否对变量与子程序名大小写敏感,必须要进行设置

;*******************************************************
;include头文件
;*******************************************************
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib

;*******************************************************
;数据段
;*******************************************************
.data
szCaption db '标题',0
szText1 db '你好,bbbb!',0
szText2 db '你好,aasaa!',0
;*******************************************************
;代码段
;*******************************************************
.code
main proc
xor eax,eax
.if eax
invoke MessageBoxA,NULL,offset szText1,offset szCaption,MB_OK
.else
invoke MessageBoxA,NULL,offset szText2,offset szCaption,MB_ICONSTOP
.endif
invoke ExitProcess,0
main endp

end

使用vs本地调试器后 会自动编译成exe 如果再生成的话会提示错误

img

但是在这里 创建进程后没法运行这个asmDemo.exe 最后发现需要将常量参数在执行前存一下

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
#include <stdio.h>
#include <Windows.h>

void main() {

STARTUPINFO info ={sizeof(info)};
GetStartupInfo(&info);
PROCESS_INFORMATION pinfo = {0};

//WinExec("C:\\Users\\test\\Desktop\\AsmDEMO.exe", SW_SHOW);
TCHAR szPath[] = TEXT("C:\\Users\\test\\Desktop\\AsmDEMO.exe");
CreateProcess(szPath,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&info,&pinfo);

void* p = 0x00D02030; //起始地址 OD查看
short oldbyte = malloc(2); //原来的 分配两个字节
oldbyte = 0x1574; //小段存储 7415 原机器码
short* newbyte = malloc(2); //新修改的

HANDLE hd = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pinfo.dwProcessId);

ReadProcessMemory(hd, p,newbyte,2,NULL ); //从p开始读2个字节到cache缓冲区

if (oldbyte != *newbyte) {
printf("不对,无法添加补丁 %p",newbyte);
}
else {
*newbyte = 0x9090; // nop机器码为90
WriteProcessMemory(hd, p, newbyte, 2, NULL);
}

//修改后变为 bbbb

}
img

中断

int中断
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
#include <stdio.h>
#include <Windows.h>
#include <TlHelp32.h>

/*
eflags寄存器 tf=1 cpu进入单步中断
*/

unsigned char int3 = 0xcc;
char* 要下断点的地址 = 0x00D0202C; //void类型的地址无法做运算 要改成char型
unsigned char 原来的机器码 = 0;

void* 补丁地址 = 0x00D02030;
unsigned short 补丁 = 0x9090; //nop

unsigned char code = 0;
void main() {

STARTUPINFO info = { sizeof(info) };
GetStartupInfo(&info);
PROCESS_INFORMATION pinfo;

TCHAR szPath[] = TEXT("C:\\Users\\test\\Desktop\\AsmDEMO.exe");
CreateProcess(szPath, NULL, NULL, NULL, NULL, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &info, &pinfo);


CONTEXT 线程上下文; //存放各种寄存器

DEBUG_EVENT dbevent;
while (1)
{
WaitForDebugEvent(&dbevent, INFINITE);

if (dbevent.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) { //被调试 退出
break;
}
if (dbevent.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) { //进程被创建时
ReadProcessMemory(pinfo.hProcess, 要下断点的地址, &原来的机器码, 1, NULL);
WriteProcessMemory(pinfo.hProcess, 要下断点的地址, & int3, 1, NULL);
printf("aaa\n");
//返回在ecx中
}
//当被调试进程发生异常事件,被调试进程开始执行第一条指令前 本事件发生一次发生
//以后只有 单步中断 和 断点中断 才会发生本事件

else if(dbevent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) {
printf("bbb\n");
if (dbevent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { // 如果是断点中断 in3中断(cc)

线程上下文.ContextFlags = CONTEXT_FULL; //context_full全部寄存器 context_segment段寄存器

GetThreadContext(pinfo.hThread, &线程上下文); //获取当前线程上下文

if (线程上下文.Eip == 要下断点的地址 + 1) {
WriteProcessMemory(pinfo.hProcess, 要下断点的地址, &原来的机器码, 1 ,NULL); //将原来的写回去
printf("ccc\n");
线程上下文.Eip--;
SetThreadContext(pinfo.hThread,&线程上下文);
WriteProcessMemory(pinfo.hProcess, 补丁地址, &补丁, 2, NULL);
}
}
}

ContinueDebugEvent(dbevent.dwProcessId, dbevent.dwThreadId, DBG_CONTINUE);

}
CloseHandle(pinfo.hProcess);
CloseHandle(pinfo.hThread);

}
img
单步中断

效果和在dosbox上的-t 单步中断相似

eflags寄存器 tf=1 cpu进入单步中断 然后tf会再置为0

eflags中tf在第九位 eflags | 0x100

img

在上面的基础上完善

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
77
78
79
80
81
82
83
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>
#include <TlHelp32.h>

unsigned char int3 = 0xcc;
char* 要下断点的地址 = 0x00D0202C; //void类型的地址无法做运算 要改成char型
unsigned char 原来的机器码 = 0;

void* 补丁地址 = 0x00D02030;
unsigned short 补丁 = 0x9090; //nop

unsigned char code = 0;
void main() {

STARTUPINFO info = { sizeof(info) };
GetStartupInfo(&info);
PROCESS_INFORMATION pinfo;

TCHAR szPath[] = TEXT("C:\\Users\\test\\Desktop\\AsmDEMO.exe");
CreateProcess(szPath, NULL, NULL, NULL, NULL, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &info, &pinfo);

CONTEXT 线程上下文; //存放各种寄存器

DEBUG_EVENT dbevent;
while (1)
{
WaitForDebugEvent(&dbevent, INFINITE);

if (dbevent.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) { //被调试 退出
break;
}
if (dbevent.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) { //进程被创建时
ReadProcessMemory(pinfo.hProcess, 要下断点的地址, &原来的机器码, 1, NULL);
WriteProcessMemory(pinfo.hProcess, 要下断点的地址, &int3, 1, NULL);
//printf("aaa\n");
//返回在ecx中
}
//当被调试进程发生异常事件,被调试进程开始执行第一条指令前 本事件发生一次发生
//以后只有 单步中断 和 断点中断 才会发生本事件

else if (dbevent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) {
//printf("bbb\n");
if (dbevent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { // 如果是断点中断 in3中断(cc)

线程上下文.ContextFlags = CONTEXT_FULL; //context_full全部寄存器 context_segment段寄存器
GetThreadContext(pinfo.hThread, &线程上下文); //获取当前线程上下文

if (线程上下文.Eip == 要下断点的地址 + 1) {
WriteProcessMemory(pinfo.hProcess, 要下断点的地址, &原来的机器码, 1, NULL); //将原来的写回去
//printf("ccc\n");
线程上下文.Eip--;
线程上下文.EFlags |= 0x100; //设置单步中断
SetThreadContext(pinfo.hThread, &线程上下文);

}
}

else if(dbevent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP) //如果是单步中断
{
线程上下文.ContextFlags = CONTEXT_FULL; //context_full全部寄存器 context_segment段寄存器
GetThreadContext(pinfo.hThread, & 线程上下文);
putchar('-');
char ch = '0';
scanf("%c", &ch); //输入一个字符
getchar();//回车
printf("寄存器eip:%08x eflags:%08x esp:%08x\n", 线程上下文.Eip, 线程上下文.EFlags, 线程上下文.Esp);

//进入单步中断后 tf会再置为0 所以要在重新设置为1
线程上下文.EFlags |= 0x100;
SetThreadContext(pinfo.hThread, &线程上下文);

}

}

ContinueDebugEvent(dbevent.dwProcessId, dbevent.dwThreadId, DBG_CONTINUE);

}
CloseHandle(pinfo.hProcess);
CloseHandle(pinfo.hThread);

}
img

欢迎关注我的其它发布渠道

------------- 💖 🌞 本 文 结 束 😚 感 谢 您 的 阅 读 🌞 💖 -------------