跳至主要内容

30.注入代码

什么是机器码,机器码与汇编的关系?

  1. 什么是机器码
    机器码也叫机器语言,是 CPU 能够直接识别并且执行的指令,全部由 0 和 1 组成,是程序在硬件上真实存在的形式。
    平时为了方便查看,机器码经常写成十六进制。机器码人很难阅读和手写,不同 CPU 架构,比如 x86、ARM,它们的机器码互不兼容。
    举个例子,x86 下把数字 1 送入 eax 寄存器,对应的机器码二进制是一串 01 比特,十六进制是 B8 01 00 00 00。
  2. 什么是汇编语言
    汇编是机器码的助记符号,用简短英文符号替代晦涩的二进制。
    比如 mov eax,1,mov 就是助记符,代表数据移动,eax 和 1 是操作数。
    汇编是给人看的文本,CPU 不能直接运行汇编源码。
  3. 二者之间的关系
    绝大多数情况下汇编指令和机器码是一一对应的,一条汇编指令就对应一条机器码指令。
    汇编源代码不能直接交给 CPU,需要汇编器这个工具做翻译,把 asm 汇编源码转换成二进制的机器码目标文件。
    这里要区分高级语言,C 语言的一行代码会生成很多条机器码,而汇编是一对一翻译。

复制代码的编写原则

  1. 不能有全局变量
  2. 不能使用常量字符串
  3. 不能使用系统调用
  4. 不能嵌套调用其他函数
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <stdio.h>
#include <Windows.h>

typedef struct
{
DWORD_PTR dwCreateAPIAddr;
LPCSTR lpFileName;
DWORD dwDesiredAccess;
DWORD dwShareMode;
LPSECURITY_ATTRIBUTES lpSecurityAttributes;
DWORD dwCreationDisposition;
DWORD dwFlagsAndAttributes;
HANDLE hTemplateFile;
HANDLE hFileResult;
}CREATEFILE_PARAM;

typedef HANDLE(WINAPI* PFN_CreateFile)(
LPCSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
DWORD __stdcall CreateFileThreadProc(LPVOID lParam)
{
CREATEFILE_PARAM* Gcreate = (CREATEFILE_PARAM*)lParam;
PFN_CreateFile pfnCreateFile;

pfnCreateFile = (PFN_CreateFile)Gcreate->dwCreateAPIAddr;
Gcreate->hFileResult = pfnCreateFile(
Gcreate->lpFileName,
Gcreate->dwDesiredAccess,
Gcreate->dwShareMode,
Gcreate->lpSecurityAttributes,
Gcreate->dwCreationDisposition,
Gcreate->dwFlagsAndAttributes,
Gcreate->hTemplateFile
);
return 0;
}

BOOL RemoteCreateFile(DWORD dwProcessID, char* szFilePathName)
{
BOOL bRet;
DWORD dwThread;
HANDLE hProcess;
HANDLE hThread;
DWORD dwThreadFunSize;
CREATEFILE_PARAM GCreateFile;
LPVOID lpFilePathName;
LPVOID lpRemoteThreadAddr;
LPVOID lpFileParamAddr;
BYTE* dwFunAddr;
HMODULE hModule;

bRet = FALSE;
hProcess = 0;
dwThreadFunSize = 0x400;
//获取进程句柄
hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, dwProcessID);
if (hProcess == NULL)
{
return FALSE;
}

//分配三段内存:存储参数、线程函数、文件名
lpFilePathName = VirtualAllocEx(hProcess, NULL, strlen(szFilePathName) + 1, MEM_COMMIT, PAGE_READWRITE);
lpRemoteThreadAddr = VirtualAllocEx(hProcess, NULL, dwThreadFunSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
lpFileParamAddr = VirtualAllocEx(hProcess, NULL, sizeof(CREATEFILE_PARAM), MEM_COMMIT, PAGE_READWRITE);
//分配失败检查
if (lpFilePathName == NULL || lpRemoteThreadAddr == NULL || lpFileParamAddr == NULL)
{
if (lpFilePathName != NULL) VirtualFreeEx(hProcess, lpFilePathName, 0, MEM_RELEASE);
if (lpRemoteThreadAddr != NULL) VirtualFreeEx(hProcess, lpRemoteThreadAddr, 0, MEM_RELEASE);
if (lpFileParamAddr != NULL) VirtualFreeEx(hProcess, lpFileParamAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
//初始化CreateFile参数
GCreateFile.dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
GCreateFile.dwShareMode = 0;
GCreateFile.lpSecurityAttributes = NULL;
GCreateFile.dwCreationDisposition = OPEN_ALWAYS;
GCreateFile.dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
GCreateFile.hTemplateFile = NULL;
//获取CreateFile地址
hModule = LoadLibraryA("kernel32.dll");
GCreateFile.dwCreateAPIAddr = (DWORD_PTR)GetProcAddress(hModule, "CreateFileA");
FreeLibrary(hModule);
//初始化CreateFile文件名
GCreateFile.lpFileName = (LPSTR)lpFilePathName;
//修改线程函数其实地址
dwFunAddr = (BYTE*)CreateFileThreadProc;
if (*dwFunAddr == 0xE9)
{
dwFunAddr = dwFunAddr + 5 + *(int*)(dwFunAddr + 1);
}
//开始复制
if (!WriteProcessMemory(hProcess, lpFilePathName, szFilePathName, strlen(szFilePathName) + 1, 0) ||
!WriteProcessMemory(hProcess, lpRemoteThreadAddr, dwFunAddr, dwThreadFunSize, 0) ||
!WriteProcessMemory(hProcess, lpFileParamAddr, &GCreateFile, sizeof(CREATEFILE_PARAM), 0))
{
VirtualFreeEx(hProcess, lpFilePathName, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, lpRemoteThreadAddr, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, lpFileParamAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
//创建远程线程
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteThreadAddr, lpFileParamAddr, 0, &dwThread);
if (hThread == NULL)
{
VirtualFreeEx(hProcess, lpFilePathName, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, lpRemoteThreadAddr, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, lpFileParamAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
//等待远程线程结束并释放远程内存
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, &dwThread);
printf("远程线程退出码: 0x%08X\n", dwThread);
ReadProcessMemory(hProcess, lpFileParamAddr, &GCreateFile, sizeof(CREATEFILE_PARAM), 0);
printf("CreateFileA 返回值: %p (INVALID_HANDLE_VALUE = %p)\n",
GCreateFile.hFileResult, INVALID_HANDLE_VALUE);
CloseHandle(hThread);
VirtualFreeEx(hProcess, lpFilePathName, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, lpRemoteThreadAddr, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, lpFileParamAddr, 0, MEM_RELEASE);
CloseHandle(hProcess);
return TRUE;
}

int main()
{
char name[] = "xxxxx\\test.txt";
if (RemoteCreateFile(34460, name))
printf("注入成功\n");
else
printf("注入失败,错误码: 0x%X\n", GetLastError());
return 0;
}
  • VS项目需要切换到Release模式

关于本文

由 GuQing 撰写,采用 CC BY-NC 4.0 许可协议。