流沙团
[实例]远程加载DLL, 远程卸载DLL
2018-1-22 流沙团


0x01 项目说明



实现在内存中对dll的加载和卸载



0x02 软件展示



360截图20180122000944649.jpg



0x03 代码展示






// TestInjectProcess.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "resource.h"
#include <Windows.h>
#include <Tlhelp32.h>
#include <assert.h>
#include <string.h>
#include <tchar.h>
#include <stdlib.h>
#include <stdio.h>


//提升进程权限
BOOL EnableDebugPrivilege(BOOL bEnable)
{
BOOL status=FALSE;
HANDLE hToken;
//打开当前进程的访问令牌
if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken))
{
LUID uID;
LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&uID);
//调整特权级别
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount =1;
tp.Privileges[0].Luid=uID;
tp.Privileges[0].Attributes=bEnable?SE_PRIVILEGE_ENABLED:0;
AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(tp),NULL,NULL);
status =(GetLastError() ==ERROR_SUCCESS);
CloseHandle(hToken);
}
return status;
}


//获取进程name的ID
DWORD getPid(LPTSTR name)
{
HANDLE hProcSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//获取进程快照句柄
assert(hProcSnap!=INVALID_HANDLE_VALUE);
PROCESSENTRY32 pe32;
pe32.dwSize=sizeof(PROCESSENTRY32);
BOOL flag=Process32First(hProcSnap,&pe32);//获取列表的第一个进程
while(flag)
{
if(!_tcscmp(pe32.szExeFile,name))
{
CloseHandle(hProcSnap);
return pe32.th32ProcessID;//pid
}
flag=Process32Next(hProcSnap,&pe32);//获取下一个进程
}
CloseHandle(hProcSnap);
return 0;
}

//卸载dll
BOOL ExitDll(DWORD dwID, LPSTR szDllName)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, dwID);
if ( !hProcess ) {
return FALSE;
}
int cByte = (_tcslen(szDllName)+1) * sizeof(TCHAR);
LPVOID pAddr = VirtualAllocEx(hProcess, NULL, cByte, MEM_COMMIT, PAGE_READWRITE);
if ( !pAddr || !WriteProcessMemory(hProcess, pAddr, szDllName, cByte, NULL)) {
return FALSE;
}
#ifdef _UNICODE
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetModuleHandleW;
#else
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetModuleHandleA;
#endif
//Kernel32.dll总是被映射到相同的地址
if ( !pfnStartAddr ) {
return FALSE;
}
DWORD dwThreadID = 0,dwFreeId=0,dwHandle;
HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, pfnStartAddr, pAddr, 0, &dwThreadID);
if ( !hRemoteThread ) {
return FALSE;
}
WaitForSingleObject(hRemoteThread,INFINITE);
// 获得GetModuleHandle的返回值
GetExitCodeThread(hRemoteThread,&dwHandle);
CloseHandle(hRemoteThread);
// 使目标进程调用FreeLibrary,卸载DLL
#ifdef _UNICODE
PTHREAD_START_ROUTINE pfnFreeAddr = (PTHREAD_START_ROUTINE)FreeLibrary;
#else
PTHREAD_START_ROUTINE pfnFreeAddr = (PTHREAD_START_ROUTINE)FreeLibrary;
#endif
HANDLE hFreeThread = CreateRemoteThread(hProcess, NULL, 0, pfnFreeAddr,(LPVOID)dwHandle,0,&dwFreeId);
if ( !hFreeThread ) {
return FALSE;
}
WaitForSingleObject(hFreeThread,INFINITE);
VirtualFreeEx(hProcess,pAddr,cByte,MEM_COMMIT);
CloseHandle(hFreeThread);
CloseHandle(hProcess);
return TRUE;

}

// 向目标进程地址空间写入DLL名称
BOOL InjectDll(HANDLE hProcess, LPSTR lpszDll)
{
DWORD dwSize, dwWritten;
//HANDLE hProcess = (HANDLE)hTProcess;
dwSize = lstrlenA(lpszDll) + 1;
LPVOID lpBuf = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE );
if (NULL == lpBuf)
{
CloseHandle(hProcess);
return FALSE;
}
if (WriteProcessMemory(hProcess, lpBuf, (LPVOID)lpszDll, dwSize, &dwWritten))
{
if(dwWritten!=dwSize)
{
VirtualFreeEx(hProcess, lpBuf, dwSize,MEM_DECOMMIT);
CloseHandle(hProcess); // 失败处理
return FALSE;
}
}
else
{
CloseHandle(hProcess);
}

// 使目标进程调用LoadLibrary,加载DLL

DWORD dwID;
LPVOID pFunc = LoadLibraryA;
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0,(LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &dwID);

if(hThread == NULL)
{
return FALSE;
}


//收尾工具
WaitForSingleObject(hThread,INFINITE);
// 释放目标进程中申请的空间
VirtualFreeEx(hProcess,lpBuf,dwSize,MEM_DECOMMIT);
CloseHandle(hThread);
CloseHandle(hProcess);

// 等待LoadLibrary加载完毕
return TRUE;
}



BOOL CALLBACK InjectDialogProc(
HWND hwndDlg, // handle to dialog box
UINT uMsg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
TCHAR szStrTemp[256]={0};
DWORD ProcessId=0;
TCHAR szProcess[10]={0};
TCHAR szDllStr[256]={0};
TCHAR szExitDllStr[256]={0};
HANDLE hProcess;
BOOL isInject;
BOOL isExit;

switch(uMsg)
{
case WM_INITDIALOG:
break;
case WM_CLOSE:
EndDialog(hwndDlg,0);
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDC_BUTTON_INJECT:
//MessageBox(0,"inject","注入",0);

GetDlgItemText(hwndDlg,IDC_EDIT_PROCESSNAME,szStrTemp,256);
ProcessId = getPid(szStrTemp);
if(ProcessId == 0)
{
MessageBox(0,"没找到进程","错误1",0);
return FALSE;
}

//打开目标进程
hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
PROCESS_VM_WRITE, FALSE, ProcessId);

if(hProcess == NULL)
{
MessageBox(0,"进程打开失败","错误2",0);
return FALSE;

}

//sprintf(szProcess,"%d",ProcessId);
//MessageBox(0,szProcess,"进程ID",MB_OK);
//写入进程的内存中去
GetDlgItemText(hwndDlg,IDC_EDIT_DLLLOCATION,szDllStr,256);

isInject =InjectDll(hProcess,szDllStr);
if(!isInject)
{
MessageBox(0,"注入DLL失败","错误\3",0);
return FALSE;
}
break;

case IDC_BUTTON_EXITDLL:
//EndDialog(hwndDlg,0);
GetDlgItemText(hwndDlg,IDC_EDIT_PROCESSNAME,szStrTemp,256);
ProcessId = getPid(szStrTemp);
if(ProcessId == 0)
{
MessageBox(0,"没找到进程","错误1",0);
return FALSE;
}
/*
hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, ProcessId);
if(hProcess == NULL)
{
MessageBox(0,"进程打开失败","错误2",0);
return FALSE;

}
*/
GetDlgItemText(hwndDlg,IDC_EDIT_DLLLOCATION,szExitDllStr,256);
//MessageBox(0,szExitDllStr,"卸载测试",MB_OK);
isExit = ExitDll(ProcessId,szExitDllStr);
if(!isExit)
{
MessageBox(0,"卸载Dll失败","错误5",0);
return FALSE;

}
break;


}
}
}

return FALSE;
}


int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
EnableDebugPrivilege(TRUE);
DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG_MAIN),NULL,InjectDialogProc);
return 0;
}








0x04 分析



因为代码基本参考一些文章编写的



在写卸载dll的时候, 遇到了很多问题, 因为对几个函数还不是太熟悉



写下来,继续分析一下吧!!







错误代码一:






void CDllManageDlg::UnInjectDll(DWORD dwPid, char *szDllName)
{
// 使目标进程调用GetModuleHandle,获得DLL在目标进程中的句柄
DWORD dwHandle;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
LPVOID pFunc = GetModuleHandleA;
char lpBuf[MAXBYTE];
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &dwPid );
// 等待GetModuleHandle运行完毕
WaitForSingleObject( hThread, INFINITE );
// 获得GetModuleHandle的返回值
GetExitCodeThread( hThread, &dwHandle );
// 释放目标进程中申请的空间
int dwSize = strlen(szDllName) + sizeof(char);
VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );
CloseHandle( hThread );
// 使目标进程调用FreeLibrary,卸载DLL
pFunc = FreeLibrary;
hThread = CreateRemoteThread( hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)pFunc, (LPVOID)dwHandle, 0, &dwPid );
// 等待FreeLibrary卸载完毕
WaitForSingleObject( hThread, INFINITE );
CloseHandle( hThread );
CloseHandle( hProcess );
}






错误代码二:






// 使目标进程调用GetModuleHandle,获得DLL在目标进程中的句柄
DWORD dwHandle, dwID;
LPVOID pFunc = GetModuleHandleA;
HANDLE hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, lpBuf, 0, &dwID );
// 等待GetModuleHandle运行完毕
WaitForSingleObject( hThread, INFINITE );
// 获得GetModuleHandle的返回值
GetExitCodeThread( hThread, &dwHandle );
// 释放目标进程中申请的空间
VirtualFreeEx( hProcess, lpBuf, dwSize, MEM_DECOMMIT );
CloseHandle( hThread );
// 使目标进程调用FreeLibrary,卸载DLL
pFunc = FreeLibrary;
hThread = CreateRemoteThread( hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, (LPVOID)dwHandle, 0, &dwID );
// 等待FreeLibrary卸载完毕
WaitForSingleObject( hThread, INFINITE );
CloseHandle( hThread );
CloseHandle( hProcess );










这两端代码, 继续分析一下







睡觉, 明天早起, 继续分析,, LP在催了,,,







标注:20180123:



已经分析完毕, 第一段代码的



lpBuf 没有指定模块名字(没有进行任何模块的分配)

第二段代码类似,



lpBuf 没有指定

流程的话

我认为应该的执行顺序是



VirtualAllocEx



WriteProcessMemory



CreateRemoteThread



获取返回值:dwHandle



CreateRemoteThread - FreeLibrary



VirtualFreeEx



后面两个代码, 不太符合要求







这是我的理解, 后面测试成功!







完整项目代码,下载地址:



TestInjectProcess.rar







待分析, 明天继续!!

















发表评论:
昵称

邮件地址 (选填)

个人主页 (选填)

内容