April 21, 2022

关于逆向工程核心原理-汇编注入

(简称逆向工程核心原理的第二十八章的学习)

汇编语言注入代码

首先借助OllyDbg的汇编功能,使用汇编语言编写注入代码(ThreadProc函数)

汇编语言写出的代码比C语言更加自由、灵活(如可以直接访问栈,寄存器的功能)

编写 ThreadProc() 函数

先来几个小tips

Fill with NOP’s

记得关掉这个选项,若我们输入的汇编机器码长度少于源汇编的长度就自动填充NOP,但是我们并不需要所以关掉这个选项

(若有误录,转到相应地址重新输入即可!)

image-20220421161937750

输入字符串可以用Crtl + E在ASCII码那栏直接输入(记得00结尾

image-20220421163119730

当这样输入字符串之后,会出现这种结果,因为我们在代码段输入字符串,当然会这样

还有种可能是变灰了,Ctrl + A让dbg重新分析,会变成字符串(这也是外调试之一!)

然而那样会导致后面全都识别为字符串,于是我们可以右键 -> Analysis -> Remove analysis from module,再度恢复

image-20220421163729692

然后由此直接写要注入的汇编ThreadProc

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
push ebp
mov ebp,esp
mov esi,dword ptr ss:[ebp+0x8]
push 0x6C6C
push 0x642E3233
push 0x72657375
push esp
call dword ptr ds:[esi]
push 0x41786F ; 注意小端序
push 0x42656761
push 0x7373654D
push esp
push eax
call dword ptr ds:[esi+0x4]
push 0x0
call 00401038 ; 将下面字符串的首地址压入堆栈 并跳到下个要执行的指令
P.Z!\x00
call 00401048 ; 与上面同理
PPPPZ.NET\x00
push 0
call eax
xor eax,eax
mov esp,ebp
pop ebp
retn

为了改成自己的熟悉了不少细节

image-20220421204053186

编写完成后,右键 -> Copy to executable -> All modifications -> Copy all -> 右键 -> save file

即可保存到原文件,再拖到010,算一下基地址转换即可找到我们所写的汇编ThreadProc()

image-20220421204950651

1
2
3
4
data = open("C:\\Users\\Pz\\Desktop\\asmtest_Patch.exe", "rb").read()
data = list([data[0x400 + i] for i in range(0x52)])
for t in data:
print(hex(t), end = ", ")

学以致用,期末的时候也许会狠狠刷一遍python数据处理,不过怎么转大写还不知道(强迫症再度上线

InjectionAssembly.exe

和之前的代码注入都差不多,写下注意就不多explain了

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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// CodeInjection2.cpp
// reversecore@gmail.com
// http://www.reversecore.com

#include "windows.h"
#include "stdio.h"

typedef struct _THREAD_PARAM
{
FARPROC pFunc[2]; // LoadLibraryA(), GetProcAddress()
} THREAD_PARAM, * PTHREAD_PARAM;

BYTE g_InjectionCode[] =
{
0x55, 0x8b, 0xec, 0x8b, 0x75, 0x8, 0x68, 0x6c, 0x6c, 0x0, 0x0, 0x68, 0x33, 0x32, 0x2e, 0x64, 0x68, 0x75, 0x73, 0x65, 0x72, 0x54, 0xff, 0x16, 0x68, 0x6f, 0x78, 0x41, 0x0, 0x68, 0x61, 0x67, 0x65, 0x42, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x54, 0x50, 0xff, 0x56, 0x4, 0x6a, 0x0, 0xe8, 0x5, 0x0, 0x0, 0x0, 0x50, 0x2e, 0x5a, 0x21, 0x0, 0xe8, 0xb, 0x0, 0x0, 0x0, 0x50, 0x50, 0x50, 0x50, 0x5a, 0x2e, 0x4e, 0x45, 0x54, 0x0, 0x0, 0x6a, 0x0, 0xff, 0xd0, 0x33, 0xc0, 0x8b, 0xe5, 0x5d, 0xc3
};

BOOL SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)
{
TOKEN_PRIVILEGES tp;
HANDLE hToken;
LUID luid;

if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken))
{
printf("OpenProcessToken error: %u\n", GetLastError());
return FALSE;
}

if (!LookupPrivilegeValue(NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError());
return FALSE;
}

tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;

// Enable the privilege or disable all privileges.
if (!AdjustTokenPrivileges(hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError());
return FALSE;
}

if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}

return TRUE;
}

BOOL InjectCode(DWORD dwPID)
{
HMODULE hMod = NULL;
THREAD_PARAM param = { 0, };
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
LPVOID pRemoteBuf[2] = { 0, };

hMod = GetModuleHandleA("kernel32.dll");

// set THREAD_PARAM
param.pFunc[0] = GetProcAddress(hMod, "LoadLibraryA");
param.pFunc[1] = GetProcAddress(hMod, "GetProcAddress");

// Open Process
if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, // dwDesiredAccess
FALSE, // bInheritHandle
dwPID))) // dwProcessId
{
printf("OpenProcess() fail : err_code = %d\n", GetLastError());
return FALSE;
}

// Allocation for THREAD_PARAM
if (!(pRemoteBuf[0] = VirtualAllocEx(hProcess, // hProcess
NULL, // lpAddress
sizeof(THREAD_PARAM), // dwSize
MEM_COMMIT, // flAllocationType
PAGE_READWRITE))) // flProtect
{
printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError());
return FALSE;
}

if (!WriteProcessMemory(hProcess, // hProcess
pRemoteBuf[0], // lpBaseAddress
(LPVOID)&param, // lpBuffer
sizeof(THREAD_PARAM), // nSize
NULL)) // [out] lpNumberOfBytesWritten
{
printf("WriteProcessMemory() fail : err_code = %d\n", GetLastError());
return FALSE;
}

// Allocation for ThreadProc()
if (!(pRemoteBuf[1] = VirtualAllocEx(hProcess, // hProcess
NULL, // lpAddress
sizeof(g_InjectionCode), // dwSize
MEM_COMMIT, // flAllocationType
PAGE_EXECUTE_READWRITE))) // flProtect
{
printf("VirtualAllocEx() fail : err_code = %d\n", GetLastError());
return FALSE;
}

if (!WriteProcessMemory(hProcess, // hProcess
pRemoteBuf[1], // lpBaseAddress
(LPVOID)&g_InjectionCode, // lpBuffer
sizeof(g_InjectionCode), // nSize
NULL)) // [out] lpNumberOfBytesWritten
{
printf("WriteProcessMemory() fail : err_code = %d\n", GetLastError());
return FALSE;
}

if (!(hThread = CreateRemoteThread(hProcess, // hProcess
NULL, // lpThreadAttributes
0, // dwStackSize
(LPTHREAD_START_ROUTINE)pRemoteBuf[1],
pRemoteBuf[0], // lpParameter
0, // dwCreationFlags
NULL))) // lpThreadId
{
printf("CreateRemoteThread() fail : err_code = %d\n", GetLastError());
return FALSE;
}

WaitForSingleObject(hThread, INFINITE);

CloseHandle(hThread);
CloseHandle(hProcess);

return TRUE;
}

int main(int argc, char* argv[])
{
DWORD dwPID = 0;

if (argc != 2)
{
printf("\n USAGE : %s <pid>\n", argv[0]);
return 1;
}

// change privilege
if (!SetPrivilege(SE_DEBUG_NAME, TRUE))
return 1;

// code injection
dwPID = (DWORD)atol(argv[1]);
InjectCode(dwPID);

return 0;
}

Debug ThreadProc

记事本拉入 -> F9跑起来 -> ALT + O 开启新线程就断 -> InjectionAssembly.exe PID -> 开调

(要素过多.jpg)

image-20220421205805561

记录几个关键点

1. 小端序与00截断

注意栈,push ebp就是指向字符串的指针了

image-20220421210048116

还有这的字符串与进程句柄

image-20220421210313803

2. 有趣的CALL

众所周知call就是push + jmp,这里把字符串首地址push到堆栈再跳到下个地址(这个属实出个题不错,这两天怎么看啥都能出题

不能单步更emmmm,不然会直接卡住,直接F4到 0x260048 才能继续调试

image-20220421210458433

吼吼,P.Z!

image-20220421210732087

记录一下2022 4/21 21:07正式学习完逆向工程核心原理第三部分

前两年的十八岁生日也是今天!说实话今天凌晨还失眠了,胃稍微有点不舒服,也许是两年前的生日,至两年后的你!

现在天天海克斯科技跑步加时空飞行哈哈哈哈,现在随笔都喜欢记录在各种笔记里头,我想记在哪记在哪!

不经想起看那些书作者的生活小随笔了,希望以后自己也能写本书;)

DASCTF X SU
🍬
HFCTF2022
🍪

About this Post

This post is written by P.Z, licensed under CC BY-NC 4.0.