为了某个目的,我设计一些简单的实验,最后做了一下笔记,以下是笔记内容。
C#程序在运行时是通过JIT临时编译而成,所以每次函数编译后的代码存放在一个随机的内存地址,如果我们想使用C进行HOOK,则需要取得这个随机地址。
首先对这个现象进行观察:
1、创建观察对象,这里我选择命令行应用就足够了
2、将默认生成的代码稍作修改
这里用到了C#中的反射方法拿到test函数地址
这个test也是后续我们用来测试hook的函数
运行之后,我们可以看到这个函数地址。
其中0x2AA098A地址开始显然是我们的test代码逻辑,说明这个函数位置找对了,且临时编译的代码也是寻常的汇编字节码,并不是具有虚拟意义的字节码,这样也就是说寻常的二进制字节码只要插入这段内存,就可以修改原本的程序逻辑,剩下的问题就只有如何定位这段代码了。
在重复运行后可以观察得到,每次临时编译后的临时代码也是相同的。
基于上述观察不难得到两种定位的思路
第一种:通过C++/CLI的特性,同样使用反射也能够拿到编译后的函数地址。
第二种:通过快速搜索内存的方法,直接搜索临时代码的特征。
为了测试我的HOOK方法是否好用,那么随便写个远程线程注入吧,毕竟重点不在这。
由于是做实验,我这里的路径什么的就很随意的写死了。
创建一个C++的DLL项目,需要修改一下项目配置
打开公共语言运行时支持
一致性模式选择NO
然后编写DLL代码
从输出中看到这种定位是成功的
直接上代码
可以看到结果,确实能够快速定位到目标函数
HOOK部分各种HOOk姿势其实都是可以的,我这里就用我用的比较顺手的钩子库MinHook
为了看到效果,我们修改一下C# ,让他不停调用test函数
最后看到效果
通过上述的一些简单实验,不难看出,就算是C#这种即时编译的语言,我们依旧可以从底层去做一些攻防相关的事情
依我拙见,接下来可以做的事情有:
1、由于即时编译的特性,只要函数被调用了,就会在内存的某一块地方存在相应的汇编代码。内存快速查找可以方便的定位到特征,这一点可以做很多事,比如反病毒、反木马、游戏关键逻辑修改等等。
2、有一点骚的想法是我自己注我自己,C#的功能或许可以通过上述的方式,在注入时把对应的目标汇编代码加密,然后把解密函数写到HOOK的部分,甚至把部分功能拆开写,一部分写到HOOK的逻辑里,这样的程序功能仍然能够保证,但是单独分析C#程序和注入用的DLL就比较难发现完整的逻辑,两个文件彼此之间也没有太强的联系。我认为这一点也同样可以用在攻防里。
3、。。。。
想做的事情很多,还得一个个实验过去,慢慢来吧。
using System;
using System.Reflection;
namespace DemoAlice
{
class
Program
{
static public void Main(string[] args)
{
test(
123
);
while
(true)
{
MethodInfo mi
=
typeof(Program).GetMethod(
"test"
);
Console.WriteLine(string.
Format
(
"{0:X8}"
, (
int
)mi.MethodHandle.GetFunctionPointer()));
}
}
static public void test(
int
num)
{
int
a, b, c;
a
=
0x20
;
b
=
0x10
;
c
=
a
+
b;
Console.WriteLine(
"someThing : "
+
num.ToString());
}
}
}
using System;
using System.Reflection;
namespace DemoAlice
{
class
Program
{
static public void Main(string[] args)
{
test(
123
);
while
(true)
{
MethodInfo mi
=
typeof(Program).GetMethod(
"test"
);
Console.WriteLine(string.
Format
(
"{0:X8}"
, (
int
)mi.MethodHandle.GetFunctionPointer()));
}
}
static public void test(
int
num)
{
int
a, b, c;
a
=
0x20
;
b
=
0x10
;
c
=
a
+
b;
Console.WriteLine(
"someThing : "
+
num.ToString());
}
}
}
int
main()
{
DWORD Pid
=
0
;
printf(
"PID : "
);
scanf_s(
"%d"
, &Pid);
HANDLE hProc
=
OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
char fileName[
100
]
=
"C:\\Users\\admin\\source\\repos\\DemoAlice\\Debug\\injectordll.dll"
;
LPVOID pszLibFileRemote
=
VirtualAllocEx(hProc, NULL,
0x100
, MEM_COMMIT, PAGE_READWRITE);
DWORD n
=
WriteProcessMemory(hProc, pszLibFileRemote, fileName,
60
, NULL);
PTHREAD_START_ROUTINE pfnThreadRtn
=
(PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L
"Kernel32"
),
"LoadLibraryA"
);
HANDLE hThread
=
CreateRemoteThread(hProc, NULL,
0
, pfnThreadRtn, pszLibFileRemote,
0
, NULL);
CloseHandle(hProc);
system(
"pause"
);
}
int
main()
{
DWORD Pid
=
0
;
printf(
"PID : "
);
scanf_s(
"%d"
, &Pid);
HANDLE hProc
=
OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
char fileName[
100
]
=
"C:\\Users\\admin\\source\\repos\\DemoAlice\\Debug\\injectordll.dll"
;
LPVOID pszLibFileRemote
=
VirtualAllocEx(hProc, NULL,
0x100
, MEM_COMMIT, PAGE_READWRITE);
DWORD n
=
WriteProcessMemory(hProc, pszLibFileRemote, fileName,
60
, NULL);
PTHREAD_START_ROUTINE pfnThreadRtn
=
(PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(L
"Kernel32"
),
"LoadLibraryA"
);
HANDLE hThread
=
CreateRemoteThread(hProc, NULL,
0
, pfnThreadRtn, pszLibFileRemote,
0
, NULL);
CloseHandle(hProc);
system(
"pause"
);
}
/
/
dllmain.cpp : Defines the entry point
for
the DLL application.
using namespace System;
using namespace Reflection;
void showTest()
{
Type
^
type
=
Type
::GetType(
"DemoAlice.Program,DemoAlice"
);
MethodInfo^ method
=
type
-
>GetMethod(
"test"
, BindingFlags::Static | BindingFlags::Public);
PVOID address
=
(PVOID)method
-
>MethodHandle.GetFunctionPointer();
char DebugString[
1024
]
=
{
0
};
sprintf_s(DebugString,
1024
,
"[+] : 0x%x\r\n"
, address);
OutputDebugStringA(DebugString);
sprintf_s(DebugString,
1024
,
"[+] : 0x%x\r\n"
,
*
(DWORD
*
)address);
OutputDebugStringA(DebugString);
}
BOOL
APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
HANDLE hThread;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hThread
=
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)showTest, NULL, NULL, NULL);
CloseHandle(hThread);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break
;
}
return
TRUE;
}
/
/
dllmain.cpp : Defines the entry point
for
the DLL application.
using namespace System;
using namespace Reflection;
void showTest()
{
Type
^
type
=
Type
::GetType(
"DemoAlice.Program,DemoAlice"
);
MethodInfo^ method
=
type
-
>GetMethod(
"test"
, BindingFlags::Static | BindingFlags::Public);
PVOID address
=
(PVOID)method
-
>MethodHandle.GetFunctionPointer();
char DebugString[
1024
]
=
{
0
};
sprintf_s(DebugString,
1024
,
"[+] : 0x%x\r\n"
, address);
OutputDebugStringA(DebugString);
sprintf_s(DebugString,
1024
,
"[+] : 0x%x\r\n"
,
*
(DWORD
*
)address);
OutputDebugStringA(DebugString);
}
BOOL
APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
HANDLE hThread;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hThread
=
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)showTest, NULL, NULL, NULL);
CloseHandle(hThread);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break
;
}
return
TRUE;
}
void showTest()
{
SYSTEM_INFO sysinfo
=
{
0
};
GetSystemInfo(&sysinfo);
char
*
p
=
(char
*
)sysinfo.lpMinimumApplicationAddress;
MEMORY_BASIC_INFORMATION meminfo
=
{
0
};
DWORD targetAddr
=
0
;
char DebugString[
1024
]
=
{
0
};
while
(p < sysinfo.lpMaximumApplicationAddress)
{
size_t size
=
VirtualQueryEx((HANDLE)
-
1
, p, &meminfo, sizeof(MEMORY_BASIC_INFORMATION));
if
(size !
=
sizeof(MEMORY_BASIC_INFORMATION))
break
;
if
(meminfo.Protect
=
=
PAGE_EXECUTE_READWRITE)
{
int
addr
=
(
int
)meminfo.BaseAddress;
for
(
int
i
=
0
; i < meminfo.RegionSize; i
+
+
)
{
if
(
*
(BYTE
*
)(addr
+
i)
=
=
0x55
&&
*
(BYTE
*
)(addr
+
i
+
1
)
=
=
0x8B
&&
*
(BYTE
*
)(addr
+
i
+
2
)
=
=
0xEC
&&
*
(BYTE
*
)(addr
+
i
+
3
)
=
=
0x83
&&
*
(BYTE
*
)(addr
+
i
+
4
)
=
=
0xEC
&&
*
(BYTE
*
)(addr
+
i
+
5
)
=
=
0x1C
&&
*
(BYTE
*
)(addr
+
i
+
6
)
=
=
0x33
&&
*
(BYTE
*
)(addr
+
i
+
7
)
=
=
0xC0
&&
*
(BYTE
*
)(addr
+
i
+
8
)
=
=
0x89
&&
*
(BYTE
*
)(addr
+
i
+
9
)
=
=
0x45
&&
*
(BYTE
*
)(addr
+
i
+
10
)
=
=
0xEC
&&
*
(BYTE
*
)(addr
+
i
+
11
)
=
=
0x89
&&
*
(BYTE
*
)(addr
+
i
+
12
)
=
=
0x45
&&
*
(BYTE
*
)(addr
+
i
+
13
)
=
=
0xE8
&&
*
(BYTE
*
)(addr
+
i
+
14
)
=
=
0x89
&&
*
(BYTE
*
)(addr
+
i
+
15
)
=
=
0x45
&&
*
(BYTE
*
)(addr
+
i
+
16
)
=
=
0xE4
&&
*
(BYTE
*
)(addr
+
i
+
17
)
=
=
0x89
&&
*
(BYTE
*
)(addr
+
i
+
18
)
=
=
0x4D
&&
*
(BYTE
*
)(addr
+
i
+
19
)
=
=
0xFC
)
{
targetAddr
=
addr
+
i;
break
;
}
}
}
p
+
=
meminfo.RegionSize;
if
(targetAddr)
break
;
}
sprintf_s(DebugString,
1024
,
"[+] : 0x%x\r\n"
, targetAddr);
OutputDebugStringA(DebugString);
}
BOOL
APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
HANDLE hThread;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hThread
=
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)showTest, NULL, NULL, NULL);
CloseHandle(hThread);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break
;
}
return
TRUE;
}
void showTest()
{
SYSTEM_INFO sysinfo
=
{
0
};
GetSystemInfo(&sysinfo);
char
*
p
=
(char
*
)sysinfo.lpMinimumApplicationAddress;
MEMORY_BASIC_INFORMATION meminfo
=
{
0
};
DWORD targetAddr
=
0
;
char DebugString[
1024
]
=
{
0
};
while
(p < sysinfo.lpMaximumApplicationAddress)
{
size_t size
=
VirtualQueryEx((HANDLE)
-
1
, p, &meminfo, sizeof(MEMORY_BASIC_INFORMATION));
if
(size !
=
sizeof(MEMORY_BASIC_INFORMATION))
break
;
if
(meminfo.Protect
=
=
PAGE_EXECUTE_READWRITE)
{
int
addr
=
(
int
)meminfo.BaseAddress;
for
(
int
i
=
0
; i < meminfo.RegionSize; i
+
+
)
{
if
(
*
(BYTE
*
)(addr
+
i)
=
=
0x55
&&
*
(BYTE
*
)(addr
+
i
+
1
)
=
=
0x8B
&&
*
(BYTE
*
)(addr
+
i
+
2
)
=
=
0xEC
&&
*
(BYTE
*
)(addr
+
i
+
3
)
=
=
0x83
&&
*
(BYTE
*
)(addr
+
i
+
4
)
=
=
0xEC
&&
*
(BYTE
*
)(addr
+
i
+
5
)
=
=
0x1C
&&
*
(BYTE
*
)(addr
+
i
+
6
)
=
=
0x33
&&
*
(BYTE
*
)(addr
+
i
+
7
)
=
=
0xC0
&&
*
(BYTE
*
)(addr
+
i
+
8
)
=
=
0x89
&&
*
(BYTE
*
)(addr
+
i
+
9
)
=
=
0x45
&&
*
(BYTE
*
)(addr
+
i
+
10
)
=
=
0xEC
&&
*
(BYTE
*
)(addr
+
i
+
11
)
=
=
0x89
&&
*
(BYTE
*
)(addr
+
i
+
12
)
=
=
0x45
&&
*
(BYTE
*
)(addr
+
i
+
13
)
=
=
0xE8
&&
*
(BYTE
*
)(addr
+
i
+
14
)
=
=
0x89
&&
*
(BYTE
*
)(addr
+
i
+
15
)
=
=
0x45
&&
*
(BYTE
*
)(addr
+
i
+
16
)
=
=
0xE4
&&
*
(BYTE
*
)(addr
+
i
+
17
)
=
=
0x89
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2021-10-14 01:56
被zx_730666编辑
,原因: 错别字订正