2012-06-02 53 views
3

該文件包含本地彙編代碼,並且我想在當前進程中運行它。 但我不希望創建一個真正的文件名(.com或.exe),所以我嘗試:如何在不創建新進程的情況下運行彙編代碼?

... 
using namespace std; 
typedef void bitcode(); 
void testcode(){ 
    cout<<"test"; 
}; 
int main() 
{ 
    bitcode *c=&testcode; // bitcode *c stands for the file containing the assembly code. 
    bitcode *d=reinterpret_cast<bitcode*> (malloc(20)); 
    memcpy(d, c, 20); 
    d(); // it doesn't work 
    return 0; 
}; 

然而,當我調用d(它不工作);.我想知道用C/C++做這件事的正確方法是什麼。

(我在Windows,它非常多,如果你能告訴我如何讓它在Linux上我會很感激)

非常感謝!

PS:我不「而不創建新的進程中運行可執行另一過程。」

+0

看看這些:: http://mspgcc.sourceforge.net/manual/c1308.html http://courses.engr.illinois.edu/ece390/books/labmanual/c-prog -mixing.html – Eight

+0

看來應該將內聯程序集放在C/CPP源文件中,並將其編譯到.com或.exe中,但我想在運行進程時在文件中運行彙編代碼。 – lin

+2

當你說「本地彙編代碼」時,你的意思是像'xchg eax,eax'這樣的彙編指令,還是像'0x90'這樣的彙編機器代碼? – DCoder

回答

2

在Windows上,這是代碼,我之前寫過。它至少在我的機器上適用於Win7 + VS2010。

基本思想是調用VirtualAlloc來分配帶有PAGE_EXECUTE_READWRITE標誌的內存。 並以正確的方式調用它,即保持堆棧平衡。

#include "stdafx.h" 
#include "windows.h" 


int emitcode[] = 
{0x83ec8b55,0x565340ec,0x0c758b57,0x8b087d8b, 
0x348d104d,0xcf3c8dce,0x6f0fd9f7,0x6f0fce04, 
0x0f08ce4c,0x10ce546f,0xce5c6f0f,0x646f0f18, 
0x6f0f20ce,0x0f28ce6c,0x30ce746f,0xce7c6f0f, 
0x04e70f38,0x4ce70fcf,0xe70f08cf,0x0f10cf54, 
0x18cf5ce7,0xcf64e70f,0x6ce70f20,0xe70f28cf, 
0x0f30cf74,0x38cf7ce7,0x7508c183,0xf8ae0fad, 
0x5e5f770f,0x5de58b5b,0xccccccc3}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    int *src = new int[64]; 
    int *dst = new int[64]; 
    int *dst2 = new int[64]; 

    for (int i = 0; i < 64; ++i){ 
     src[i] = i; 
    } 

    //fastercopy(dst,src, 64/2); 

    void* address = NULL; 
    address= VirtualAlloc(NULL, 
      sizeof(emitcode), 
      MEM_COMMIT|MEM_RESERVE, 
      PAGE_EXECUTE_READWRITE); 

    memcpy(address,emitcode,sizeof(emitcode)); 

    //call emit code from assemble 
    __asm { 
     push  20h 
     mov   eax,dword ptr [src] 
     push  eax 
     mov   ecx,dword ptr [dst] 
     push  ecx 
     mov   ecx, dword ptr [address] 
     call  ecx 
     add   esp,0Ch 
    } 

    for (int i = 0; i < 64; ++i){ 
     printf("%d ",dst[i]); 
    } 

    //call emit code from function pointer 
    typedef void (*FASTCALL)(void* dst, void* src, int len); 
    FASTCALL fastcall; 
    fastcall = (FASTCALL)address; 
    fastcall(dst2,src,64/2); 

    printf("\n"); 
    for (int i = 0; i < 64; ++i){ 
     printf("%d ",dst2[i]); 
    } 

    return 0; 
} 
+0

如何做到這一點,但與彙編指令代碼?例如emitcode是一個文本:移動ax,添加bx,..ect – Jigberto

4

您需要映射可寫頁面,將代碼寫入它,將頁面切換爲可執行文件,然後執行它。

+0

你是說我應該儘量避免DEP?你能告訴我如何詳細地做這件事嗎?非常感謝! – lin

+0

我不知道該怎麼做,只需要做什麼。 –

+0

請注意,雖然...有* * [錯誤的方法](http://www.akkadia.org/drepper/selinux-mem.html)做到這一點... –

4

伊格納西奧已經描述瞭如何做到這一點的大致輪廓。

由於您使用的是Windows,你需要爲這個功能是VirtualAlloc而不是malloc,特別是與PAGE_EXECUTE_READWRITE標誌獲得權限寫入內存,並執行它。

然後,根據文檔你仍然需要明確設置執行標誌使用VirtualProtect後寫入內存,並在執行之前。

最後,在使用內存之後,您需要使用VirtualFree而不是free釋放它。

std::size_t size = 20; 
void* mem = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 
// Write assembly opcodes to mem 

DWORD old_protect; 
VirtualProtect(mem, size, PAGE_EXECUTE_READWRITE, &old_protect); 
typedef (void)(*fptr)(); 
fptr f = *reinterpret_cast<fptr*>(&mem); 

f(); 

// Later … 
VirtualFree(mem, 0, MEM_RELEASE); 

注意在reinterpret_cast增加的間接。這是避免未定義行爲所必需的:C++不允許在對象指針和函數指針之間進行轉換。但是,上面的代碼是實現定義的,因此就C++而言是OK的。

此外,請注意,我省略了上面的錯誤檢查代碼,以保持簡單。您不得在實際代碼中使用。有關正確的錯誤處理的信息,請參閱文檔。

在Linux上,工作流程是類似的,只是使用不同的函數名稱。

+0

我厭倦了上面的代碼,但它仍然報告「訪問衝突」... – lin

+0

@linzuzeng查看更新。顯然''VirtualProtect'是需要的,即使權限是相同的。此外,確保您分配和保護的大小實際上足夠大,以便執行整個彙編代碼,否則執行將只會嘗試恢復到受保護區域之外。還要注意我的代碼的其他更改 - 我應該更仔細地閱讀文檔。 –

+0

奇怪的是,它也適用於我沒有VirtualProtect .. – harold

2

..既然您也問了關於linux
在這裏,您可以使用mmap
〜例如:

foo。CPP

#include <stdio.h> 
#include <string.h> 
#include <sys/mman.h> 
#include <assert.h> 

void bar(int n) { printf("bar invoked: %d\n", n); } 
typedef void(*fp_bar)(int); 

typedef union 
{ 
    unsigned char* pb; 
    void*   pv; 
    void(*pf)(); 
} 
foocodes; 

//some _unencrypted random foo code segment 
const unsigned char ar_foos[]= 
{ 
    0xbb,0x00,0x00,0x00,0x00, //mov ebx addy of a function to invoke 
    0xb8,0x0d,0x00,0x00,0x00, //mov eax 13 ~int input arg 
    0x50,      //push eax 
    0xff,0xd3,     //call absolute addy ebx 
    0x5b,      //pop 
    0x90,      //throw in a nop to make up 16 foos 
    0xC3      //return 
}; 


int main() 
{ 
    size_t foos_size=sizeof ar_foos; 
    foocodes ufoos; 
    fp_bar pbar=&bar; 
    assert(4==sizeof pbar); //example requires a 32bit fn address 

    ufoos.pv=mmap(
     NULL, 
     foos_size, 
     PROT_WRITE|PROT_EXEC, 
     MAP_PRIVATE|MAP_ANONYMOUS, 
     -1, 
     0); 

    memcpy(ufoos.pv, ar_foos, foos_size);  
    memcpy(ufoos.pb+1, &pbar, sizeof pbar); //poke in the bar fn address 

    ufoos.pf(); //invoke foo codes 

    return munmap(ufoos.pv, foos_size);  
} 


&這裏的命令行的東西:

$ uname -a 
Linux violet-313 3.0.0-19-generiC#33-Ubuntu SMP Thu Apr 19 19:05:57 UTC 2012 i686 i686 i386 GNU/Linux 

$ gcc --version 
gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1 
... 

$ gcc -ofoo foo.cpp 
$ ./foo 
bar invoked: 13 

(; OOK,我也省略了錯誤的清晰的利益處理;)

相關問題