首页
论坛
课程
招聘
[旧帖] [原创] 利用远程线程将代码注入到目标进程中执行 0.00元
2011-4-18 12:04 2126

[旧帖] [原创] 利用远程线程将代码注入到目标进程中执行 0.00元

2011-4-18 12:04
2126
/* ************************************
* remote.c
* 创建远程线程、将代码注入到其他进程中执行
**************************************/
/* 头文件 */
#include <windows.h>
#include <Tlhelp32.h>

/*************************************
* BOOL EnablePrivilege (PCSTR name)
* 功能 提升本权限
*防止有些进程我们权限不够,打不开人家
* 参数 PCSTR name 所需的权限
* 返回是否成功
**************************************/
DWORD EnablePrivilege (PCSTR name)
{
HANDLE hToken;
BOOL rv;
//设置结构
TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
// 查找权限值
LookupPrivilegeValue (
  0,
  name,
  &priv.Privileges[0].Luid
  );
// 打开本进程Token
OpenProcessToken(
  GetCurrentProcess (),
  TOKEN_ADJUST_PRIVILEGES,
  &hToken
  );
// 提权
AdjustTokenPrivileges (
  hToken,
  FALSE,
  &priv,
  sizeof priv,
  0,
  0
  );
// 返回值,错误信息,如果操作成功,则应为ERROR_SUCCESS,为O
rv = GetLastError();
// 关闭Token
CloseHandle (hToken);
return rv;
}

/*************************************
* BOOL LoadRometeDll(DWORD dwProcessId, LPTSTR lpszLibName)
* 功能 通过创建远程线程给其他进程加载Dll
*
* 参数 DWORD dwProcessId 目标进程PID
*  LPTSTR lpszLibName Dll的路径
* 返回是否成功
**************************************/
BOOL LoadRometeDll(DWORD dwProcessId, LPTSTR lpszLibName)
{
BOOL   bResult          = FALSE;
HANDLE hProcess         = NULL;
HANDLE hThread          = NULL;
PSTR   pszLibFileRemote = NULL;
DWORD  cch;
PTHREAD_START_ROUTINE pfnThreadRtn;

__try
{
  // 获得想要注入代码的进程的句柄.
  hProcess = OpenProcess(
   PROCESS_ALL_ACCESS,
   FALSE,
   dwProcessId
   );

  if (hProcess == NULL)
   __leave;

  // 计算DLL路径名需要的字节数.
  cch = 1 + lstrlen(lpszLibName);

  // 在远程线程中为路径名分配空间.
  pszLibFileRemote = (PSTR)VirtualAllocEx(
   hProcess,
   NULL,
   cch,
   MEM_COMMIT,
   PAGE_READWRITE
   );

  if (pszLibFileRemote == NULL)
   __leave;

  // 将DLL的路径名复制到远程进程的内存空间.
  if (!WriteProcessMemory(
   hProcess,
   (PVOID)pszLibFileRemote,
   (PVOID)lpszLibName,
   cch,
   NULL))
   __leave;

  // 获得LoadLibraryA在Kernel32.dll中的真正地址.
  pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(
   GetModuleHandle(TEXT("Kernel32")), TEXT("LoadLibraryA"));

  if (pfnThreadRtn == NULL)
   __leave;

  // 创建远程线程,并通过远程线程调用用户的DLL文件.
  hThread = CreateRemoteThread(
   hProcess,
   NULL,
   0,
   pfnThreadRtn,
   (PVOID)pszLibFileRemote,
   0,
   NULL
   );
  if (hThread == NULL)
   __leave;

  // 等待远程线程终止.
  WaitForSingleObject(hThread, INFINITE);
  bResult = TRUE;
}
__finally
{
  // 关闭句柄.
  if (pszLibFileRemote != NULL)
   VirtualFreeEx(hProcess, (PVOID)pszLibFileRemote, 0, MEM_RELEASE);
  if (hThread  != NULL)
   CloseHandle(hThread);
  if (hProcess != NULL)
   CloseHandle(hProcess);
}
return bResult;
}
/*************************************
* BOOL GetProcessIdByName(LPSTR szProcessName, LPDWORD lpPID)
* 功能 通过进程名获取进程PID
*
* 参数 LPSTR szProcessName 进程名
*  LPDWORD lpPID  指向保存PID的变量
* 返回是否成功
**************************************/
BOOL GetProcessIdByName(LPSTR szProcessName, LPDWORD lpPID)
{
// 变量及初始化
STARTUPINFO st;
PROCESS_INFORMATION pi;
PROCESSENTRY32 ps;
HANDLE hSnapshot;
ZeroMemory(&st, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
st.cb = sizeof(STARTUPINFO);
ZeroMemory(&ps,sizeof(PROCESSENTRY32));
ps.dwSize = sizeof(PROCESSENTRY32);
// 遍历进程
hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0);
if(hSnapshot == INVALID_HANDLE_VALUE)
{
  return FALSE;
}

if(!Process32First(hSnapshot,&ps))
{
  return FALSE;
}
do
{
  // 比较进程名
  if(lstrcmpi(ps.szExeFile,"工程1.exe")==0)//为了明了这里没用szProcessName
  {
   // 找到了
   *lpPID = ps.th32ProcessID;
   CloseHandle(hSnapshot);
   return TRUE;
  }
}
while(Process32Next(hSnapshot,&ps));
// 没有找到
CloseHandle(hSnapshot);
return FALSE;
}
/*************************************
* int WinMain(
*   HINSTANCE hInstance,
*   HINSTANCE hPrevInstance,
*   LPSTR lpCmdLine,
*   int nCmdShow
*   )
**************************************/
int WINAPI WinMain(
   HINSTANCE hInstance,
   HINSTANCE hPrevInstance,
   LPSTR lpCmdLine,
   int nCmdShow
   )
{
DWORD dwPID;
// 提权,获取SE_DEBUG_NAME权限,
// 可以在其他进程的内存空间中写入、创建线程
if(0!=EnablePrivilege (SE_DEBUG_NAME))
  return 0;
// 获取目录进程的PID
if(!GetProcessIdByName("工程1.exe",&dwPID))
  return 0;
// 通过创建远程线程加载DLL
// 将msg.dll放置在系统目录下,这里是相对路径嘛
if(!LoadRometeDll(dwPID,"msg.dll"))
  return 0;
return 1;
}

/* ************************************
* msg.c
* 动态链接库
**************************************/
/* 头文件 */
#include <Windows.h>

//全局变量
   HWND hDlg;
   HWND hWnd;
   WNDPROC OldWndProc;
   //WNDPROC OldWndProc1;

   //子窗口控件的窗口过程
LRESULT CALLBACK NewWndProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
{
    STARTUPINFO si={sizeof(si)};
   //si.cb=sizeof(STARTUPINFO);
   //si.wShowWindow=SW_SHOW;
   //si.dwFlags=STARTF_USESHOWWINDOW;
   PROCESS_INFORMATION pi;
switch(Msg)
{
case WM_KEYDOWN:
  MessageBox(hWnd,"s","f",0);
  return CallWindowProc(OldWndProc,hWnd,Msg,wParam,lParam);
  //return 0;
  break;
case WM_LBUTTONDOWN:
  //MessageBox(NULL,"b","s",0);
  //SetFocus(hWnd);

  CreateProcess(NULL,"C:\\Documents and Settings\\Administrator\\桌面\\2.exe",NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi);
  return CallWindowProc(OldWndProc,hWnd,Msg,wParam,lParam);

// return 0;
  break;

default:
  return CallWindowProc(OldWndProc,hWnd,Msg,wParam,lParam);
}
return 0;
}

/*************************************
* DllMain
**************************************/
BOOL WINAPI DllMain(
     HINSTANCE hinstDLL,  // DLL模块的句柄
     DWORD fdwReason,     // 调用的情况
     LPVOID lpReserved )  // reserved
{
// 在不同的情况下都会调用DllMain函数,分别处理
switch( fdwReason )
{
  // 加载Dll
case DLL_PROCESS_ATTACH:
  {

//测试而已,无其他不良目的

   CHAR lpMainMoudleName[MAX_PATH]="sdfsfsdf";
   CHAR lpMessage[MAX_PATH+64];
   // 获取PID 和主模块名,将弹出消息框
   DWORD dwPID = GetCurrentProcessId();
   //GetModuleBaseName(GetCurrentProcess(),NULL,lpMainMoudleName,MAX_PATH);
   wsprintf(lpMessage,"Process name: %s, PID: %u ",lpMainMoudleName,dwPID);
   MessageBox(NULL,lpMessage,"msg.dll",MB_OK);
    hDlg=FindWindow(NULL,"Form1");//窗口标题Form1
    hWnd=GetDlgItem(hDlg,2);//command1的控件ID,可以借助SPY++得到
    OldWndProc=(WNDPROC)SetWindowLong(hWnd,GWL_WNDPROC,(LONG)NewWndProc);
   break;
  }
  // 新建线程
case DLL_THREAD_ATTACH:
  break;
  // 线程退出
case DLL_THREAD_DETACH:
  break;
  // 释放Dll
case DLL_PROCESS_DETACH:

  break;
}
return TRUE;
}

简单说明:

1.远程注入的代码基本都是一个模板,能够套用的,这里借助了精通WINDOWS API中的代码来完成的,注释相对比较全面了吧,为了实现特定的目标:替换VB工程中command1按钮的消息响应,因此在动态链接库中用到了窗口子类化,一点很重要的过程就是利用进程ID如何去获取窗口句柄,这里简单的用到了FINDWINDOW函数,当然方法还是有不少的,比如看雪论坛中就有类似的帖子,是自己定义一个函数来完成此功能的,可以做个参考。

2.工程1.exe是一个VB的对话框,上面放置了2个按钮,分别是command1,command2,点击会各自响应自己的消息处理过程(VB中实现的),利用上面的代码可以实现注入到这个工程1.exe程序中,结果就是当我们点击command1的时候可以响应我们自己的处理过程,比如上述就是执行了桌面上的2.exe,然后再返回默认的处理过程,这里如果注释掉return callwindowproc就只会出现我们自己的处理了,原本VB中实现的将被我们上述工程所屏蔽掉了。

3.如果想要很明显的看到效果,那完全可以先自己运行工程1.exe,然后在运行上述编译好的EXE,此时一切将不再是以前那样了,偷梁换柱已经果断实现了。

4.其实也可以把所有代码都写入到目标进程的地址空间中,这样就能避免使用DLL了,但是在DLL中实现有个很大的好处就是不需要把很复杂的东西全部writeprocessmemory到目标进程地址空间中,大大简化了实现过程。

5.顺便说一句,写的这个程序由于用到了createremotethread,所以会被金山等系列提示(大家懂的),仅仅是个试验罢了。完整的工程暂时就不上传了吧,如果有需要的话,再上传或者发邮件也可以,毕竟不是很“光彩”的东西。

第五届安全开发者峰会(SDC 2021)议题征集正式开启!

收藏
点赞0
打赏
分享
最新回复 (4)
雪    币: 81
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
gfm 活跃值 2011-4-18 13:27
2
0
这个在楼主博客看过了,支持一下
雪    币: 826
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
superdj 活跃值 2011-4-18 14:48
3
0
源码在哪里?
雪    币: 96
活跃值: 活跃值 (70)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
yiruirui 活跃值 1 2011-4-18 14:51
4
0
源码上面其实已经写的很全面了,如果还不行的话,可以发e-mail。
雪    币: 41
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
weiperry 活跃值 2011-4-18 16:37
5
0
我不太理解,远程线程注入和使用钩子的dll文件代码中直接用LoadLibrary的区别是什么?

看核心编程上CreateRemoteThread 需要GetProcAddress, VirtualAllocEx, WriteProcessMemory 这些步骤来解决在远程进程的地址访问。我一直困惑为什么不能用一个钩子dll在远程进程建一个新线程,楼主可以帮忙解决一下偶的困惑吗?
游客
登录 | 注册 方可回帖
返回