簡體   English   中英

使用 mov reg to reg 創建 shellcode 問題

[英]creating shellcode problems with mov reg to reg

好的,所以我試圖創建一個創建 shellcode 的 function。

我在處理 rex / mod 的東西時遇到了很多問題。

我目前的代碼類型的作品。

到目前為止,如果 regs 比 R8 小,它可以正常工作。

如果我使用一個較小的 reg,那么 R8 就可以了。

問題是一旦我必須 regs 小於 r8 並且相同或者如果 src 更小我會遇到問題

enum Reg64 : uint8_t {
    RAX = 0, RCX = 1, RDX = 2, RBX = 3,
    RSP = 4, RBP = 5, RSI = 6, RDI = 7,
    R8 = 8, R9 = 9, R10 = 10, R11 = 11,
    R12 = 12, R13 = 13, R14 = 14, R15 = 15
};

inline uint8_t encode_rex(uint8_t is_64_bit, uint8_t extend_sib_index, uint8_t extend_modrm_reg, uint8_t extend_modrm_rm) {
    struct Result {
        uint8_t b : 1;
        uint8_t x : 1;
        uint8_t r : 1;
        uint8_t w : 1;
        uint8_t fixed : 4;
    } result{ extend_modrm_rm, extend_modrm_reg, extend_sib_index, is_64_bit, 0b100 };
    return *(uint8_t*)&result;
}
inline uint8_t encode_modrm(uint8_t mod, uint8_t rm, uint8_t reg) {
    struct Result {
        uint8_t rm : 3;
        uint8_t reg : 3;
        uint8_t mod : 2;
    } result{ rm, reg, mod };
    return *(uint8_t*)&result;
}

    inline void mov(Reg64 dest, Reg64 src) {
        if (dest >= 8)
            put<uint8_t>(encode_rex(1, 2, 0, 1));
        else if (src >= 8)
            put<uint8_t>(encode_rex(1, 1, 0, 2));
        else
            put<uint8_t>(encode_rex(1, 0, 0, 0));

        put<uint8_t>(0x89);

        put<uint8_t>(encode_modrm(3, dest, src));
    }

    //c.mov(Reg64::RAX, Reg64::RAX); // works
    //c.mov(Reg64::RAX, Reg64::R9); // works
    //c.mov(Reg64::R9, Reg64::RAX); // works
    //c.mov(Reg64::R9, Reg64::R9); // Does not work returns (mov r9,rcx)

此外,如果沒有所有 if 的情況下有更短的方法來做到這一點,那就太好了。

僅供參考,大多數人通過使用像 NASM 這樣的普通匯編程序進行匯編來創建 shellcode,然后將該二進制文件十六進制轉儲到 C 字符串中。 編寫自己的匯編程序可能是一個有趣的項目,但基本上是一個單獨的項目。


您的encode_rex看起來有點明智,為四個位使用四個參數。 但是mov中調用它的代碼有時會傳遞2 ,這將截斷為0

此外,您用於 reg-reg 移動的 2 個相關擴展位(b 和 x)有 4 種可能性。 但是您的 if/else if/else 鏈僅涵蓋其中 3 個,忽略dest>=8 && src >= 8 => x:b = 3的可能性

由於這兩個位是正交的,您應該像這樣分別計算它們:

put<uint8_t>(encode_rex(1, 0, dest>=8, src>=8));

SIB-index x字段應始終為0 ,因為您沒有 SIB 字節,只有 ModRM 用於 reg-reg mov

您在encode_rex中混合了結構初始化程序,其中extend_modrm_reg第二位,它將初始化x字段而不是r 您的位域名稱與https://wiki.osdev.org/X86-64_Instruction_Encoding#Encoding匹配,但您使用了錯誤的 C++ 變量來初始化它們。 有關說明,請參見該鏈接。


可能我有 dest, src 順序,這取決於您使用的是mov r/m, r還是mov r, r/m操作碼。 我沒有仔細檢查哪個是哪個。

來自 NASM 的健全性檢查:我與nasm -felf64 -l/dev/stdout組裝以獲得清單:

     1 00000000 4889C8                  mov rax, rcx
     2 00000003 4889C0                  mov rax, rax
     3 00000006 4D89C0                  mov r8, r8
     4 00000009 4989C0                  mov r8, rax
     5 0000000C 4C89C0                  mov rax, r8

您使用的是 NASM 使用的相同0x89操作碼,因此您的 REX 前綴應該匹配。


return *(uint8_t*)&result; 是嚴格混疊的 UB,在 MSVC 之外不安全。

使用 memcpy 安全地鍵入雙關語。 (或聯合;大多數真實世界的 C++ 編譯器,包括 gcc/clang/MSVC 確實定義了聯合類型雙關語的行為,就像在 C99 中一樣,與 ISO C++ 不同)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM