线程注入到EXPLORER中时,导致EXPLORER 异常退出! 帮忙看下是哪里的问题!

时间:2022-11-27 00:45:50

void CTestInjectDlg::OnStart() 
{
BOOL bRet = 0 ;
DWORD dwRemotePID = 0 ;
DWORD dwWritten = 0 ;
char szRemoteProc[MAX_PATH] = {"explorer.exe"} ;
WCHAR wszRemoteProc[] = {L"c:\\aaa.exe"} ;
DWORD dwParamLen = wcslen (wszRemoteProc) + 1 ;

// 修改本进程权限
EnablePrivilege (SE_DEBUG_NAME, true) ;

//
// 获取 Explorer 进程
//
dwRemotePID = ProcessNameToId (szRemoteProc) ;
if (!dwRemotePID)
{
// 恢复本进程权限
EnablePrivilege (SE_DEBUG_NAME, false) ;
return ;
}

m_hRemoteProc = OpenProcess (PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE
                       , FALSE, dwRemotePID) ;

// 申请 线程代码所需空间
LPVOID lpThdFunc = VirtualAllocEx (m_hRemoteProc, NULL
, sizeof (BYTE) * ((int)EndFunc - (int)ThreadFunc + 1)
, MEM_COMMIT, PAGE_EXECUTE_READWRITE) ;

bRet = WriteProcessMemory (m_hRemoteProc, lpThdFunc, ThreadFunc
              , sizeof (BYTE) * ((int)EndFunc - (int)ThreadFunc), &dwWritten) ;

// 申请 参数所需空间
LPVOID lpThdParam = VirtualAllocEx (m_hRemoteProc, NULL
                              , sizeof (WCHAR) * (dwParamLen)
                                  , MEM_COMMIT, PAGE_READWRITE) ;
bRet = WriteProcessMemory (m_hRemoteProc, lpThdParam, wszRemoteProc
              , sizeof (WCHAR) * (dwParamLen), &dwWritten) ;

HANDLE hRemoteThd = CreateRemoteThread (m_hRemoteProc, NULL, 0
                        , (LPTHREAD_START_ROUTINE)lpThdFunc, lpThdParam, 0, NULL) ;

// 恢复本进程权限
EnablePrivilege (SE_DEBUG_NAME, false) ;
}


DWORD WINAPI CTestInjectDlg::ThreadFunc(LPVOID pParam)
{
WCHAR * pszCmd = (WCHAR*) pParam ;
PROCESS_INFORMATION pi = {0} ;
STARTUPINFOW si = {0} ;

si.cb = sizeof (si) ;

if (!pszCmd)
{
return 0 ;
}

if(CreateProcessW (pszCmd, NULL, NULL, NULL, NULL
             , 0, NULL, NULL, &si, &pi))
{
if (pi.hThread)
CloseHandle (pi.hThread) ;

if (pi.hProcess)
CloseHandle (pi.hProcess) ;
}
return 0 ;
}

void WINAPI CTestInjectDlg::EndFunc (void)
{
}


DWORD CTestInjectDlg::ProcessNameToId (LPCTSTR lpszProcessName)
{
 //*
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe;
    pe.dwSize = sizeof(PROCESSENTRY32);

    if (!Process32First(hSnapshot, &pe))
{
        ::MessageBox(NULL, "Process32First () 失败!", "提示", MB_ICONINFORMATION | MB_OK);
        return 0;
    }

    while (Process32Next(hSnapshot, &pe))
{
        if (!stricmp(lpszProcessName, pe.szExeFile))
{
            return pe.th32ProcessID;
        }
    }
 //*/
    return 0;
}

BOOL CTestInjectDlg::EnablePrivilege(LPCTSTR lpszPrivilegeName,BOOL bEnable)
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES |
        TOKEN_QUERY | TOKEN_READ,&hToken))
        return FALSE;
    if(!LookupPrivilegeValue(NULL, lpszPrivilegeName, &luid))
        return TRUE;

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = (bEnable) ? SE_PRIVILEGE_ENABLED : 0;

    AdjustTokenPrivileges(hToken,FALSE,&tp,NULL,NULL,NULL);

    CloseHandle(hToken);

    return (GetLastError() == ERROR_SUCCESS);
}

17 个解决方案

#1


沙发 .不懂哦

#2


谢了
鲤鱼

#3


After invoking VirtualAllocEx function, you need to further perform VirtualProtectEx to change the access protection of memory in a specified process.

#4


这个问题是由于你在远程线程函数中的api调用地址错误引起的,你这样的代码直接写过去,因为其中所有api的调用的地址都是相对于本进程指令的一个偏移地址,如果把这些指令写到其他进程空间,同样的偏移地址也许就不是这个API了,所以会出现访问为例,所以,你应该把这些api调用全部换成函数指针的形式,使他们真正指向dll中导出他们的地址,从而能够在别的进程空间运行,具体可以参见我的文章:
http://forum.eviloctal.com/read-htm-tid-21510-fpage-4.html

#5


呵呵,你这注入的思路不对,如果要做得复杂点,你就得要做好代码的重定位,包括所有全局的东东,如数据,函数调用等,这样虽然也很简单,但非常麻烦,而且还不好源代码调试

#6


楼上说得对,写这个原理简单,但是做起来很麻烦,动则牵及全身...

#7


CreateProcessW
CloseHandle
应该出在这里,没有进行重定位.幸好的是它们是Kernel32的导出函数,在每个进程的地址是一样的,所以传递参数把这两个API的地址也传过去.

#8


把要注入的代码写成一个dll,再用《windows 核心编程》里远程线程注入dll的方法就行了。

#9


// 申请 线程代码所需空间
LPVOID lpThdFunc = VirtualAllocEx (m_hRemoteProc, NULL
, sizeof (BYTE) * ((int)EndFunc - (int)ThreadFunc + 1)
, MEM_COMMIT, PAGE_EXECUTE_READWRITE) ;

bRet = WriteProcessMemory (m_hRemoteProc, lpThdFunc, ThreadFunc
, sizeof (BYTE) * ((int)EndFunc - (int)ThreadFunc), &dwWritten) ;


???

#10


DentistryDoctor(天使下地狱去是劫富济贫) ( ) 

这段代码有问题吗?
请指教!!

#11


首先谢谢兄弟们!

我的第一个问题找到了

CreateRemoteThread()
的时候没有 CREATE_SUSPEND
挂起来,在恢复后
注入成功了
但是线程执行的时候还是出错了

我想 就是兄弟们说的原因了
没有重定位API

还有   yjgx007(who's superior) ( ) 
说的 不知道 什么时候用到
我没有用到 VirtualProtectEx ()
来设置保护属性
也可以写内存的

应该和我分配内存时,用了PAGE_EXECUTE_READWRITE 和 PAGE_READWRITE
有关系吧!

再次感谢朋友们!


DentistryDoctor(天使下地狱去是劫富济贫) ( ) 

我的那段代码有什么问题,请指教一下!
谢谢

#12


为什么创建线程的时候
非要挂起一下 
才可以注入呢

#13


http://www.czvc.com/view.asp?id=333
这里有LZ遇到的问题的描述..当然这篇文章提出了LZ的问题,也是解决的.

#14


你是把代码作为远线程注入的.
那么在你的远程线程里面调用的API需要单独对其获取地址,然后把函数地址写过去再调用.

#15


http://forum.eviloctal.com/read-htm-tid-21510-fpage-4.html

楼主,注入的时候是不需要挂起的,只是启动了一个线程而已.

跟你说解决办法吧,记得给分哦:
比如你要在远程线程中使用ZwCreateProcessEx这个API,这个api是由ntdll.dll导出的.那么你首先需要定义一个指向其导出地址的函数指针,方法如下:
typedef
NTSTATUS
(__stdcall * PFN_ZWCREATEPROCESSEX)(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN LPVOID ObjectAttributes,
IN HANDLE InheritFromProcessHandle,
IN BOOLEAN InheritHandles,
IN HANDLE SectionHandle,
IN HANDLE DebugPort,
IN HANDLE ExceptionPort,
IN HANDLE reserv
);
定义远程参数:
typedef _RemoteParam{
LPVOID lpZwCreateProcessEx;
} RemoteParam, * PRemoteParam;
在你的远程线程函数中,首先定义一个函数指针,然后使其等于参数中传递过来的API的真实地址,然后直接调用那个指针就能成功调用该API了.
首先在程序中设置远程参数中的API地址:
RemoteParam Rpm;
HMODULE hNtdll = LoadLibrary("ntdll.dll");
Rpm.lpZwCreateProcessEx = GetProcAddress(hNtdll, "ZwCreateProcessEx");
在你的远程线程函数中则这么来使用该API:
PFN_ZWCREATEPROCESSEX pfnZwCreateProcessEx = Rpm->lpZwCreateProcessEx;
pfnZwCreateProcessEx(...);
这样就可以了.

注意在CreateRemoteThread的时候,要把远程线程和远程参数都要先写到目标进程空间,把参数地址传递好了.最后肯定会成功的.

这样把你的远程线程中的api调用都换成这种形式的调用,保证你的程序能成功.因为,他们CALL的都是真正的API地址,而不是一个偏移地址了.

#16


最简单的方法是: 用createRemoteThread在远程进程内load一个dll,并调用它的某个导出函数,里面实现你需要的功能,这样可以随心所欲,哈哈

#17


修改了一下
可以注入了
但线程函数执行时有异常
不知道是什么原因

#define THREADSIZE (4 * 1024)

typedef BOOL (WINAPI *PFN_CREATEPROCESSW)(LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES
                 , BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);

typedef BOOL (WINAPI *PFN_CLOSEHANDLE) (HANDLE);

typedef struct tagTHD_PARAM
{
PFN_CREATEPROCESSW pfnCreateProcessW ;
PFN_CLOSEHANDLE    pfnCloseHandle ;
LPCWSTR pExeProc ;
} THD_PARAM, *PTHD_PARAM;

THD_PARAM thdParam = {0} ;
void CTestInjectDlg::OnStart() 
{
BOOL bRet = 0 ;
DWORD dwRemotePID = 0 ;
DWORD dwWritten = 0 ;
CHAR szRemoteProc[MAX_PATH] = "explorer.exe" ;
WCHAR szExeProc[] = L"c:\\aaa.exe" ;
DWORD dwParamLen = wcslen (szExeProc) + 1 ;

// 修改本进程权限
EnablePrivilege (SE_DEBUG_NAME, true) ;

//
// 获取 Explorer 进程
//
dwRemotePID = ProcessNameToId (szRemoteProc) ;
if (!dwRemotePID)
{
// 恢复本进程权限
EnablePrivilege (SE_DEBUG_NAME, false) ;
return ;
}

m_hRemoteProc = OpenProcess (PROCESS_ALL_ACCESS/*PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE|PROCESS_VM_READ*/
                       , FALSE, dwRemotePID) ;

// 申请 线程代码所需空间
LPVOID lpThdFunc = VirtualAllocEx (m_hRemoteProc, NULL
, THREADSIZE// sizeof (BYTE) * ((int)EndFunc - (int)ThreadFunc + 1)
, MEM_COMMIT, PAGE_EXECUTE_READWRITE) ;

bRet = WriteProcessMemory (m_hRemoteProc, lpThdFunc, ThreadFunc
              , THREADSIZE/*sizeof (BYTE) * ((int)EndFunc - (int)ThreadFunc)*/, &dwWritten) ;

// 申请 参数所需空间
LPVOID lpThdParam = VirtualAllocEx (m_hRemoteProc, NULL
                              , sizeof (WCHAR) * (dwParamLen)
                                  , MEM_COMMIT, PAGE_READWRITE) ;
bRet = WriteProcessMemory (m_hRemoteProc, lpThdParam, szRemoteProc
              , sizeof (WCHAR) * (dwParamLen), &dwWritten) ;

// 获取函数地址
PFN_CREATEPROCESSW pfnCreateProcessW = NULL ;
PFN_CLOSEHANDLE    pfnCloseHandle = NULL ;
HMODULE     hDll = LoadLibrary ("kernel32.dll") ;
if (!hDll)
{
return ;
}

pfnCreateProcessW = (PFN_CREATEPROCESSW) GetProcAddress (hDll, "CreateProcessW") ;
pfnCloseHandle    = (PFN_CLOSEHANDLE)    GetProcAddress (hDll, "CloseHandle") ;

FreeLibrary (hDll) ;

// 参数赋值
thdParam.pExeProc          = (LPCWSTR)lpThdParam ;
thdParam.pfnCloseHandle    = pfnCloseHandle ;
thdParam.pfnCreateProcessW = pfnCreateProcessW ;

// 复制参数 到目标进程
LPVOID lpThdParams = VirtualAllocEx (m_hRemoteProc, NULL
                              , sizeof (thdParam)
                                  , MEM_COMMIT, PAGE_READWRITE) ;

bRet = WriteProcessMemory (m_hRemoteProc, lpThdParams, &thdParam
              , sizeof (thdParam), &dwWritten) ;

HANDLE hRemoteThd = CreateRemoteThread (m_hRemoteProc, NULL, 1024
                        , (LPTHREAD_START_ROUTINE)lpThdFunc, lpThdParams, CREATE_SUSPENDED, NULL) ;
if (hRemoteThd)
{
ResumeThread (hRemoteThd) ;
}

// 恢复本进程权限
EnablePrivilege (SE_DEBUG_NAME, false) ;
}

DWORD WINAPI CTestInjectDlg::ThreadFunc(LPVOID pParam)
{
typedef BOOL (WINAPI *PFN_CREATEPROCESSW)(LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES
                 , BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);

typedef BOOL (WINAPI *PFN_CLOSEHANDLE) (HANDLE);

typedef struct tagTHD_PARAM
{
PFN_CREATEPROCESSW pfnCreateProcessW ;
PFN_CLOSEHANDLE    pfnCloseHandle ;
LPCWSTR pExeProc ;
} THD_PARAM, *PTHD_PARAM;

PROCESS_INFORMATION pi = {0} ;
STARTUPINFOW si = {0} ;

PTHD_PARAM pthdParam = (PTHD_PARAM) pParam ;
if (pthdParam)
{
if (pthdParam->pfnCreateProcessW && pthdParam->pExeProc)
{
BOOL bRet = pthdParam->pfnCreateProcessW (pthdParam->pExeProc, NULL, NULL, NULL
, NULL, NULL, NULL, NULL, &si, &pi) ;
if (bRet && pthdParam->pfnCloseHandle
&& pi.hThread && pi.hProcess)
{
pthdParam->pfnCloseHandle (pi.hThread) ;
pthdParam->pfnCloseHandle (pi.hProcess) ;
}
}
}

return 0 ;
}

#1


沙发 .不懂哦

#2


谢了
鲤鱼

#3


After invoking VirtualAllocEx function, you need to further perform VirtualProtectEx to change the access protection of memory in a specified process.

#4


这个问题是由于你在远程线程函数中的api调用地址错误引起的,你这样的代码直接写过去,因为其中所有api的调用的地址都是相对于本进程指令的一个偏移地址,如果把这些指令写到其他进程空间,同样的偏移地址也许就不是这个API了,所以会出现访问为例,所以,你应该把这些api调用全部换成函数指针的形式,使他们真正指向dll中导出他们的地址,从而能够在别的进程空间运行,具体可以参见我的文章:
http://forum.eviloctal.com/read-htm-tid-21510-fpage-4.html

#5


呵呵,你这注入的思路不对,如果要做得复杂点,你就得要做好代码的重定位,包括所有全局的东东,如数据,函数调用等,这样虽然也很简单,但非常麻烦,而且还不好源代码调试

#6


楼上说得对,写这个原理简单,但是做起来很麻烦,动则牵及全身...

#7


CreateProcessW
CloseHandle
应该出在这里,没有进行重定位.幸好的是它们是Kernel32的导出函数,在每个进程的地址是一样的,所以传递参数把这两个API的地址也传过去.

#8


把要注入的代码写成一个dll,再用《windows 核心编程》里远程线程注入dll的方法就行了。

#9


// 申请 线程代码所需空间
LPVOID lpThdFunc = VirtualAllocEx (m_hRemoteProc, NULL
, sizeof (BYTE) * ((int)EndFunc - (int)ThreadFunc + 1)
, MEM_COMMIT, PAGE_EXECUTE_READWRITE) ;

bRet = WriteProcessMemory (m_hRemoteProc, lpThdFunc, ThreadFunc
, sizeof (BYTE) * ((int)EndFunc - (int)ThreadFunc), &dwWritten) ;


???

#10


DentistryDoctor(天使下地狱去是劫富济贫) ( ) 

这段代码有问题吗?
请指教!!

#11


首先谢谢兄弟们!

我的第一个问题找到了

CreateRemoteThread()
的时候没有 CREATE_SUSPEND
挂起来,在恢复后
注入成功了
但是线程执行的时候还是出错了

我想 就是兄弟们说的原因了
没有重定位API

还有   yjgx007(who's superior) ( ) 
说的 不知道 什么时候用到
我没有用到 VirtualProtectEx ()
来设置保护属性
也可以写内存的

应该和我分配内存时,用了PAGE_EXECUTE_READWRITE 和 PAGE_READWRITE
有关系吧!

再次感谢朋友们!


DentistryDoctor(天使下地狱去是劫富济贫) ( ) 

我的那段代码有什么问题,请指教一下!
谢谢

#12


为什么创建线程的时候
非要挂起一下 
才可以注入呢

#13


http://www.czvc.com/view.asp?id=333
这里有LZ遇到的问题的描述..当然这篇文章提出了LZ的问题,也是解决的.

#14


你是把代码作为远线程注入的.
那么在你的远程线程里面调用的API需要单独对其获取地址,然后把函数地址写过去再调用.

#15


http://forum.eviloctal.com/read-htm-tid-21510-fpage-4.html

楼主,注入的时候是不需要挂起的,只是启动了一个线程而已.

跟你说解决办法吧,记得给分哦:
比如你要在远程线程中使用ZwCreateProcessEx这个API,这个api是由ntdll.dll导出的.那么你首先需要定义一个指向其导出地址的函数指针,方法如下:
typedef
NTSTATUS
(__stdcall * PFN_ZWCREATEPROCESSEX)(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN LPVOID ObjectAttributes,
IN HANDLE InheritFromProcessHandle,
IN BOOLEAN InheritHandles,
IN HANDLE SectionHandle,
IN HANDLE DebugPort,
IN HANDLE ExceptionPort,
IN HANDLE reserv
);
定义远程参数:
typedef _RemoteParam{
LPVOID lpZwCreateProcessEx;
} RemoteParam, * PRemoteParam;
在你的远程线程函数中,首先定义一个函数指针,然后使其等于参数中传递过来的API的真实地址,然后直接调用那个指针就能成功调用该API了.
首先在程序中设置远程参数中的API地址:
RemoteParam Rpm;
HMODULE hNtdll = LoadLibrary("ntdll.dll");
Rpm.lpZwCreateProcessEx = GetProcAddress(hNtdll, "ZwCreateProcessEx");
在你的远程线程函数中则这么来使用该API:
PFN_ZWCREATEPROCESSEX pfnZwCreateProcessEx = Rpm->lpZwCreateProcessEx;
pfnZwCreateProcessEx(...);
这样就可以了.

注意在CreateRemoteThread的时候,要把远程线程和远程参数都要先写到目标进程空间,把参数地址传递好了.最后肯定会成功的.

这样把你的远程线程中的api调用都换成这种形式的调用,保证你的程序能成功.因为,他们CALL的都是真正的API地址,而不是一个偏移地址了.

#16


最简单的方法是: 用createRemoteThread在远程进程内load一个dll,并调用它的某个导出函数,里面实现你需要的功能,这样可以随心所欲,哈哈

#17


修改了一下
可以注入了
但线程函数执行时有异常
不知道是什么原因

#define THREADSIZE (4 * 1024)

typedef BOOL (WINAPI *PFN_CREATEPROCESSW)(LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES
                 , BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);

typedef BOOL (WINAPI *PFN_CLOSEHANDLE) (HANDLE);

typedef struct tagTHD_PARAM
{
PFN_CREATEPROCESSW pfnCreateProcessW ;
PFN_CLOSEHANDLE    pfnCloseHandle ;
LPCWSTR pExeProc ;
} THD_PARAM, *PTHD_PARAM;

THD_PARAM thdParam = {0} ;
void CTestInjectDlg::OnStart() 
{
BOOL bRet = 0 ;
DWORD dwRemotePID = 0 ;
DWORD dwWritten = 0 ;
CHAR szRemoteProc[MAX_PATH] = "explorer.exe" ;
WCHAR szExeProc[] = L"c:\\aaa.exe" ;
DWORD dwParamLen = wcslen (szExeProc) + 1 ;

// 修改本进程权限
EnablePrivilege (SE_DEBUG_NAME, true) ;

//
// 获取 Explorer 进程
//
dwRemotePID = ProcessNameToId (szRemoteProc) ;
if (!dwRemotePID)
{
// 恢复本进程权限
EnablePrivilege (SE_DEBUG_NAME, false) ;
return ;
}

m_hRemoteProc = OpenProcess (PROCESS_ALL_ACCESS/*PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE|PROCESS_VM_READ*/
                       , FALSE, dwRemotePID) ;

// 申请 线程代码所需空间
LPVOID lpThdFunc = VirtualAllocEx (m_hRemoteProc, NULL
, THREADSIZE// sizeof (BYTE) * ((int)EndFunc - (int)ThreadFunc + 1)
, MEM_COMMIT, PAGE_EXECUTE_READWRITE) ;

bRet = WriteProcessMemory (m_hRemoteProc, lpThdFunc, ThreadFunc
              , THREADSIZE/*sizeof (BYTE) * ((int)EndFunc - (int)ThreadFunc)*/, &dwWritten) ;

// 申请 参数所需空间
LPVOID lpThdParam = VirtualAllocEx (m_hRemoteProc, NULL
                              , sizeof (WCHAR) * (dwParamLen)
                                  , MEM_COMMIT, PAGE_READWRITE) ;
bRet = WriteProcessMemory (m_hRemoteProc, lpThdParam, szRemoteProc
              , sizeof (WCHAR) * (dwParamLen), &dwWritten) ;

// 获取函数地址
PFN_CREATEPROCESSW pfnCreateProcessW = NULL ;
PFN_CLOSEHANDLE    pfnCloseHandle = NULL ;
HMODULE     hDll = LoadLibrary ("kernel32.dll") ;
if (!hDll)
{
return ;
}

pfnCreateProcessW = (PFN_CREATEPROCESSW) GetProcAddress (hDll, "CreateProcessW") ;
pfnCloseHandle    = (PFN_CLOSEHANDLE)    GetProcAddress (hDll, "CloseHandle") ;

FreeLibrary (hDll) ;

// 参数赋值
thdParam.pExeProc          = (LPCWSTR)lpThdParam ;
thdParam.pfnCloseHandle    = pfnCloseHandle ;
thdParam.pfnCreateProcessW = pfnCreateProcessW ;

// 复制参数 到目标进程
LPVOID lpThdParams = VirtualAllocEx (m_hRemoteProc, NULL
                              , sizeof (thdParam)
                                  , MEM_COMMIT, PAGE_READWRITE) ;

bRet = WriteProcessMemory (m_hRemoteProc, lpThdParams, &thdParam
              , sizeof (thdParam), &dwWritten) ;

HANDLE hRemoteThd = CreateRemoteThread (m_hRemoteProc, NULL, 1024
                        , (LPTHREAD_START_ROUTINE)lpThdFunc, lpThdParams, CREATE_SUSPENDED, NULL) ;
if (hRemoteThd)
{
ResumeThread (hRemoteThd) ;
}

// 恢复本进程权限
EnablePrivilege (SE_DEBUG_NAME, false) ;
}

DWORD WINAPI CTestInjectDlg::ThreadFunc(LPVOID pParam)
{
typedef BOOL (WINAPI *PFN_CREATEPROCESSW)(LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES
                 , BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);

typedef BOOL (WINAPI *PFN_CLOSEHANDLE) (HANDLE);

typedef struct tagTHD_PARAM
{
PFN_CREATEPROCESSW pfnCreateProcessW ;
PFN_CLOSEHANDLE    pfnCloseHandle ;
LPCWSTR pExeProc ;
} THD_PARAM, *PTHD_PARAM;

PROCESS_INFORMATION pi = {0} ;
STARTUPINFOW si = {0} ;

PTHD_PARAM pthdParam = (PTHD_PARAM) pParam ;
if (pthdParam)
{
if (pthdParam->pfnCreateProcessW && pthdParam->pExeProc)
{
BOOL bRet = pthdParam->pfnCreateProcessW (pthdParam->pExeProc, NULL, NULL, NULL
, NULL, NULL, NULL, NULL, &si, &pi) ;
if (bRet && pthdParam->pfnCloseHandle
&& pi.hThread && pi.hProcess)
{
pthdParam->pfnCloseHandle (pi.hThread) ;
pthdParam->pfnCloseHandle (pi.hProcess) ;
}
}
}

return 0 ;
}