以掛起方式創建進程


1.進程的繼承
創建進程的函數: BOOL CreateProcess(                                
  LPCTSTR lpApplicationName,                 // 創建進程時打開的exe文件名                               
  LPTSTR lpCommandLine,                      // 創建進程時的命令行參數                               
  LPSECURITY_ATTRIBUTES lpProcessAttributes, // 安全屬性,可用來設置該進程句柄是否可繼承                                
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // 可用來設置進程的主線程句柄是否可繼承                                
  BOOL bInheritHandles,                      // 是否繼承父進程的句柄表                               
  DWORD dwCreationFlags,                     // creation flags                                
  LPVOID lpEnvironment,                      // new environment block                                
  LPCTSTR lpCurrentDirectory,                // 進程的當前目錄                                
  LPSTARTUPINFO lpStartupInfo,               // 程序狀態設置                                
  LPPROCESS_INFORMATION lpProcessInformation // out參數進程信息                                
);                        
lpProcessAttributes    ->安全屬性,用來設定進程是否能被繼承;一個SECURITY_ATTRIBUTES結構的指針,第三個成員為TRUE可繼承;
lpThreadAttributes    ->安全屬性,線程能否被繼承;SECURITY_ATTRIBUTES結構指針,第三個成員為TRUE可繼承;
dwCreationFlags        ->創建標記;如果是控制台程序,CREATE_NEW_CONSOLE表示子進程和父進程都有自己的控制台窗口;為NULL則子進程會把信息打印到父進程的控制台;
lpCurrentDirectory    ->進程的當前目錄;如果為NULL,子進程的當前目錄將和父進程一樣;
                                        如果想要當前目錄為子進程exe文件所在目錄,則需要用字符串指定;
 
獲取進程當前目錄:
char szBuffer[256] = {0};
GetCurrentDirectory(256,szBuffer);
printf("%s\n",szBuffer);

 

當在進程A中CreateProcess創建一個子進程B時,進程A的句柄表中會多有兩個條記錄,一個是進程B的內核對象句柄,一個是B主線程的內核對象句柄;   
如果lpProcessAttributes、lpThreadAttributes都為NULL;則兩個句柄都不可繼承,也就是可繼承狀態為0;
進程A句柄表:
此時如果在進程A中創建一個子進程C,那么C將不能繼承A的進程內核和線程內核句柄;
但如果將進程B設為可繼承,那么C可以從A的句柄表中繼承到B的進程句柄和主線程句柄;
利用這一特點可以在進程C中空值進程B;
 
1)目標
在A進程中創建一個進程(比如瀏覽器進程IE),並設定該子進程的進程內核句柄與主線程內核句柄為可繼承                                
在A進程中再創建一個進程B,在B中對IE進程控制    
 
2)進程B
#include<stdio.h>
#include<windows.h>
 
int main(int argc, char* argv[]){
    DWORD dwProcessHandle = -1;                        
    DWORD dwThreadHandle = -1;                        
    char szBuffer[256] = {0};                        
                            
    memcpy(szBuffer,argv[1],8);                        
    sscanf(szBuffer,"%x",&dwProcessHandle);                        
                            
    memset(szBuffer,0,256);                        
    memcpy(szBuffer,argv[2],8);                        
    sscanf(szBuffer,"%x",&dwThreadHandle);                        
                            
    printf("獲取IE進程、主線程句柄\n");                        
    Sleep(2000);                        
    //掛起主線程                        
    printf("掛起主線程\n");                        
    ::SuspendThread((HANDLE)dwThreadHandle);                        
    Sleep(5000);                        
                            
    //恢復主線程                        
    ::ResumeThread((HANDLE)dwThreadHandle);                        
    printf("恢復主線程\n");                        
    Sleep(5000);                        
                            
    //關閉ID進程                        
    ::TerminateProcess((HANDLE)dwProcessHandle,1);                        
    ::WaitForSingleObject((HANDLE)dwProcessHandle, INFINITE);                        
                            
    printf("ID進程已經關閉.....\n");                        
    return 0;
}
 
3)進程A
#include<stdio.h>
#include<windows.h>
 
int main(int argc, char* argv[]){
    char szHandle[8] = {0};    
    char szBuffer[256] = {0};                             
                                
    SECURITY_ATTRIBUTES ie_sa_p;                            
    ie_sa_p.nLength = sizeof(ie_sa_p);                            
    ie_sa_p.lpSecurityDescriptor = NULL;                            
    ie_sa_p.bInheritHandle = TRUE;                             
                                
    SECURITY_ATTRIBUTES ie_sa_t;                            
    ie_sa_t.nLength = sizeof(ie_sa_t);                            
    ie_sa_t.lpSecurityDescriptor = NULL;                            
    ie_sa_t.bInheritHandle = TRUE;                             
    //創建一個可以被繼承的內核對象,此處是個進程                            
    STARTUPINFO ie_si = {0};                               
    PROCESS_INFORMATION ie_pi;                            
    ie_si.cb = sizeof(ie_si);                            
                                
    TCHAR szCmdline[] =TEXT("c://program files//internet explorer//iexplore.exe");                            
    CreateProcess(                            
        NULL,                         
        szCmdline,                         
        &ie_sa_p,                         
        &ie_sa_t,                         
        TRUE,                         
        CREATE_NEW_CONSOLE,                         
        NULL,                         
        NULL, &ie_si, &ie_pi);                         
    
    //組織命令行參數                            
    sprintf(szHandle,"%x %x",ie_pi.hProcess,ie_pi.hThread);                            
    sprintf(szBuffer,"D:/create_child.exe %s",szHandle);                            
                                
    //定義創建進程需要用的結構體                            
    STARTUPINFO si = {0};                               
    PROCESS_INFORMATION pi;                            
    si.cb = sizeof(si);                            
                                
    //創建子進程                            
    BOOL res = CreateProcess(                            
        NULL,                         
        szBuffer,                         
        NULL,                         
        NULL,                         
        TRUE,        //可以繼承父進程的句柄表                     
        CREATE_NEW_CONSOLE,                         
        NULL,                         
        NULL, &si, &pi);                         
                                                
    return 0;
}
 
4)結果
運行進程A,ie瀏覽器被打開;然后被進程B結束,瀏覽器關閉;
 
2.以掛起的方式創建進程
用CreateProcess函數可以創建一個進程;
正常情況下CreateProcess做以下事情:創建一個進程的內核對象、給進程分配一個4GB的空間、加載pe:包括exe、dll、修復dll、創建主線程,把程序入口地址交給EIP
 
如果參數dwCreationFlags傳入CREATE_SUSPENDED將以掛起的方式創建進程;
以這種方式創建的進程只有一個殼;也就是進程的主線程沒有開始運行;
需要調用函數讓進程的主線程恢復執行:
ResumeThread(ie_pi.hThread);
 
1)已掛起方式打開進程實例
例如:以掛起方式打開notpad++
#include<stdio.h>
#include<windows.h>
 
int main(int argc, char* argv[]){
    TCHAR szAppName[256] = TEXT("D:\\Program Files\\Notepad++\\notepad++.exe");
    STARTUPINFO si = {0};    //程序啟動設置
    si.cb = sizeof(si);    //只需要傳遞結構大小即可
    PROCESS_INFORMATION pi;    //記錄進程句柄信息等
    ::CreateProcess(
        NULL,
        szAppName,
        NULL,
        NULL,
        FALSE,
        CREATE_SUSPENDED,
        NULL,
        NULL,
        &si,
        &pi
    );
    //恢復主進程
    //::ResumeThread(pi.hThread);
    return 0;
}
當沒有恢復主進程時,notepad++沒有運行;
但任務管理器中可以看到notpad++的進程,只不過占內存比正常運行小,因為主線程根本沒運行;
 
當調用ResumeThread恢復主進程時,notepad++正常運行
 
2)關於加殼
掛起方式創建的進程之是一個外殼;
我們可以修改外殼程序的內容;
這意味着在程序調用ResumeThread恢復執行的時候,外殼還是notepad++,但里面的內容完全變了;
可以將自己的程序拉伸為鏡像文件,然后替換外殼程序,接下來恢復執行時執行的就是自己的程序了;
這就是所謂的加殼;
 
想以這種借助其它程序的外殼來執行程序時,必須將外殼進程的主線程入口和ImageBase給替換掉;
入口地址=程序的鏡像基址ImageBase + 程序的入口函數地址OEP;
 
因為外殼程序已掛起的方式運行的;
也就是說外殼主線程是掛起的,可以得到主線程上下文對象CONTEXT;
CONTEXT contx;  
contx.ContextFlags = CONTEXT_FULL;      //CONTEXT_FULL表示除了寄存器的值,還要得到其他信息
GetThreadContext(pi.hThread, &contx);    //第一個參數為主線程句柄,主線程句柄在進程創建后會存在PROCESS_INFORMATION結構中;

 

然后就可以通過CONTEXT結構獲取程序入口點
//獲取入口點
DWORD dwEntryPoint = contx.Eax;    //eax中存儲的入口點並不一定是ImageBase+oep,而是真正的入口點;
                                   //當程序不是占據ImageBase時,入口點將不等於ImageBase+oep;
//獲取ImageBase
char* baseAddress = (CHAR *) contx.Ebx+8;    //這里的baseAddress不能直接輸出
這里獲取的baseAddress並不是想要的ImageBase,而是ImageBase存在哪里;
但父進程並不能直接通過這個地址找到ImageBase,因為這是子進程中的地址;
需要用到進程間讀取的函數:ReadProcessMemory;
5個參數依次為:進程句柄、從這進程的什么位置開始讀、讀的東西放到哪里、讀多少個字節、(out參數)真正讀了多少個字節;
TCHAR szBuffer[256];
memset(szBuffer,0,256);
ReadProcessMemory(pi.hProcess,baseAddress,szBuffer,4,NULL);
這樣就得到了需要修改的外殼進程的入口點和ImageBase;
接下來想借殼上市只需要做相應的修改即可;  
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM