滴水逆向笔记系列-win32总结9-61.CE使用-62.ShellCode_远程线程注入

第六十一课 CE使用

下载完CE后用ce自带的小作业练练

1.第二题

先打开进程
image.png
First scan搜索100,发现有很多100,我们先让右边程序Hit me,然后Next scan搜索96,发现已经搜出来了,正常数据会很多,就需要继续改继续搜,最后点击下面value修改为1000即可
image.png

2.第三题

先New Scan搜索小于500的,
image.png
点击右边的Hit me,看到-7,Next Scan搜索减了7的数值,发现还有三个,
image.png
再点一次,Next Scan搜索减了5的数值,最后和第二题一样修改数值即可500
image.png

3.第四题

这题主要就是类型的选择
image.png

4.第五题

找到数据在哪后点这里可以看哪个地址对该数值进行写入
image.png

image.png

5.第六题

看到上两行代码可以发现rdx其实是由325AD0地址里面的值决定的,eax的值就是被赋值到rdx地址里面
image.png
所以我们直接去看325AD0地址里面的值
image.png

6.第七题

这里找到减一的代码后需要把他修改代码的意义,比如修改成加一
修改代码时需注意硬编码的数量要保持不变,我们需要修改的代码如果比原来少,我们可以使用nop代替,需要修改的代码如果比原来多,我们可以使用jmp到其他地址执行我们的代码然后再jmp回来
image.png

7.第八题(重点)

先找出数据的地址,看一下代码,eax应该就是存放数值的寄存器,数据存放到[rsi+18]这个地址,我们想找到数据存放的基址
image.png
看下面寄存器信息可以看到rsi为015960F0,搜一下这个地址存放的地址,发现有两个,跟踪这两个地址的访问情况,可以看到01613B10在点击改变数值是有访问记录的,说明这个地址才是我们需要的image.png
可以看到语句是mov rsi,[rsi],rsi015960F0就是[rsi]01613B10这个地址放的,可以看到没有偏移,所以我们继续搜01613B10是谁放的
image.png
mov rsi,[rsi+18] ,rsi01613B10是[rsi+18]069AB6C8地址存放的,再跟踪一下[rsi+18]的rsi是哪里存放的
:为什么我是跟踪后面的rsi,因为mov rsi,[rsi+18]意思就是把[rsi+18]的数值赋值给rsi,我们上面搜索的是01613B10是谁赋值的,所以01613B10就是rsi,[rsi+18]就是我们想搜的地址,谁存放的rsi
image.png
可以看到有10的偏移,所以我们搜索015FB280-10,最后得出基址100325B00,基址就是绿色的,也是一个具体的值
image.png
所以得出最后的思路公式[[[[100325B00]+10]+18]]+18
image.png

第六十二课 ShellCode_远程线程注入

1.ShellCode

ShellCode其实就是放在哪都可以执行的硬编码。
因为可能会有两种情况:

  • 硬编码里含有全局变量,当硬编码放到其他进程后,由于全局变量是写死的绝对地址,所以那个绝对地址在其他进程中是找不到
  • 硬编码里的函数如果直接使用,在反汇编里面其实是call [0x123456],这个0x123456就是iat表,但是当这个硬编码拿到其他进程中时,他可能在0x123456找不到iat表,函数也就用不了了

2.远程线程注入

HANDLE WINAPI CreateThread(				
    LPSECURITY_ATTRIBUTES lpThreadAttributes,				
    SIZE_T dwStackSize,				
    LPTHREAD_START_ROUTINE lpStartAddress,				
    LPVOID lpParameter,				
    DWORD dwCreationFlags,				
    PDWORD lpThreadId				
    );				
				
HANDLE WINAPI CreateRemoteThread(				
    HANDLE hProcess,				
    LPSECURITY_ATTRIBUTES lpThreadAttributes,				
    SIZE_T dwStackSize,				
    LPTHREAD_START_ROUTINE lpStartAddress,				
    LPVOID lpParameter,				
    DWORD dwCreationFlags,				
    LPDWORD lpThreadId				
    );			

目标:把模块(dll,exe)通过进程B写入到进程A里面
image.png
思路:进程B使用CreateRemoteThread函数在进程A远程创建一个线程,这个线程使用
LoadLibrary()函数加载模块
问题:这里有四个问题

  • 一个是远程线程调用函数CreateRemoteThread函数的调用函数是有格式需要的
  • 一个是线程函数的地址怎么获取
  • 一个是线程函数的参数(即我们想要加载的模块名字的字符串地址怎么获取
  • dll加载进进程A后,我们怎么得到dll的首地址,因为使用dll我们需要dll的地址

回答问题

  • LoadLibrary()的函数格式刚好和要求的一样(DWORD和HMODULE一样)
线程函数结构:	
typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(					
    LPVOID lpThreadParameter					
    );					

LoadLibarary()的函数格式:
HMODULE	WINAPI LoadLibraryA(					
    LPCSTR lpLibFileName					
    );	
  • LoadLibrary()函数的地址在进程A和进程B是一样的
  • 模块名字的字符串地址就直接在进程B中写入模块名字字符串顺便获取地址,使用函数VirtualAllocEx()WriteProcessMemory()
  • HINSTANCE hModule = LoadLibrary("InjectDll.dll"); ,自己加载dll我们可以使用变量接收,等待线程函数结束, 获取线程退出码,即LoadLibrary的返回值,即dll的首地址,因为我们自己写线程函数的时候退出码就是我们返回的值
  • 最后释放为DLL名字申请的空间VirtualFreeEx() 关闭句柄CloseHandle()

代码

#include <Windows.h>
#include <stdio.h>

BOOL SetDebugPrivilege()
{
	HANDLE hToken;
	TOKEN_PRIVILEGES tokenPrivileges;
	BOOL result = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
	if (!result)
		return FALSE;

	result = LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tokenPrivileges.Privileges[0].Luid);
	if (!result)
	{
		CloseHandle(hToken);
		return FALSE;
	}

	tokenPrivileges.PrivilegeCount = 1;
	tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

	result = AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, sizeof(tokenPrivileges), NULL, NULL);
	CloseHandle(hToken);

	return result;
}

int main()
{
	/*if (!SetDebugPrivilege())
	{
		printf("无法设置调试特权\n");
		return 0;
	}*/


	//获取进程id
	HANDLE Hpid = ::OpenProcess(PROCESS_ALL_ACCESS, NULL, 3292);
	//获取LoadLibarary地址
	HMODULE LibHandle = LoadLibrary("kernel32");
	if (LibHandle == NULL) {
		printf("无法加载kernel32模块\n");
		return 0;
	}
	else
	{
		printf("加载模块成功\n");
	}
	FARPROC ProcAdd = GetProcAddress(LibHandle, "LoadLibraryA");
	if (ProcAdd == NULL) {
		printf("无法获取LoadLibrary地址\n");
		return 0;
	}
	else
	{
		printf("获取地址成功\n");
	}
	//写入进程A LoadLibarary字符串并获取地址
	LPVOID Buffer = VirtualAllocEx(Hpid, NULL, 256, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (Buffer == NULL) {
		printf("申请空间失败,可能需要重定位\n");
		return 0;
	}
	else
	{
		printf("申请空间成功\n");
	}
	TCHAR CharBuffer[256] = "injectDll.dll";
	DWORD CharAddress = WriteProcessMemory(Hpid, Buffer, CharBuffer, 256, NULL);

	//远程创建线程
	HANDLE HRemoteThread = ::CreateRemoteThread(Hpid, NULL, 0, (LPTHREAD_START_ROUTINE)ProcAdd, Buffer, 0, NULL);
	printf("错误码: %d\n", GetLastError());
	//WaitForSingleObject(HRemoteThread, INFINITE);
	//获取线程退出码
	DWORD ExitCode;
	GetExitCodeProcess(HRemoteThread, &ExitCode);

	getchar();
}

posted @ 2024-03-17 17:23  小新07  阅读(77)  评论(0编辑  收藏  举报