/* ************************************
* 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,所以会被金山等系列提示(大家懂的),仅仅是个试验罢了。完整的工程暂时就不上传了吧,如果有需要的话,再上传或者发邮件也可以,毕竟不是很“光彩”的东西。