[toc]

一、在C语言中直接使用数组执行机器指令

1.写一个C语言程序,内容为调用MessageBoxA弹出一个消息框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <string.h>
#include <windows.h>

void MessageC()
{
MessageBoxA(0,"MessageC", 0, 0);
return;
}

int main()
{
MessageC();
return 0;
}

2.写一个C语言程序,内容为使用x86内联汇编调用MessageBoxA弹出一个消息框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <string.h>
#include <windows.h>


void MessageA()
{
char *message = "MessageA";
_asm {
mov eax,message
push 0
push 0
push eax
push 0
mov eax,MessageBoxA
call eax
}
return;
}
int main()
{
MessageA();

return 0;
}

3. 写一个x86 C语言程序,使用数组调用MessageBoxA弹出一个消息框

  1. 将汇编指令转换为机器码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    char mcode[] = {
    0x6A,0x00, //push 0
    0x6A,0x00, //push 0
    0x6A,0x00, //push 0
    0x6A,0x00, //push 0
    0xB8,0x50,0xAF,0x37,0x77, //mov eax, 7737AF50h
    0xFF,0xD0, //call eax
    0xC3 //ret
    };
  2. 编写代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <string.h>
#include <windows.h>


void MessageM()
{
char mcode[] = {
0x6A,0x00, //push 0
0x6A,0x00, //push 0
0x6A,0x00, //push 0
0x6A,0x00, //push 0
0xB8,0x50,0xAF,0x37,0x77, //mov eax, 7737AF50h
0xFF,0xD0, //call eax
0xC3 //ret
};
int (*func)() = (int (*)())mcode;
//更改内存属性为可读可写可执行
DWORD dwOldProtect = 0;
VirtualProtectEx(GetCurrentProcess(), (LPVOID)&mcode, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwOldProtect);
func();
return;
}
int main()
{
MessageM();
return 0;
}

4. 64位C语言程序,使用数组调用汇编指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
#include <string.h>
#include <windows.h>


int inc1()
{
// 定义机器码
// 将数组转换为函数指针
// 注意:这可能会导致未定义行为
unsigned char code[] = {
0x48, 0x31, 0xC0, // xor rax, rax
0x48, 0xFF, 0xC0, // inc rax
0xC3 // ret
};
//更改内存属性为可读可写可执行
DWORD dwOldProtect = 0;
VirtualProtectEx(GetCurrentProcess(), (LPVOID)&code, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwOldProtect);
int (*funcp)() = (int (*)())code;
return funcp();
}

void functiona()
{
// 调用机器码
int result = inc1();
printf("Result: %x\n", result); // 应该输出 1,因为我们将 rax 设为 1
}

int main()
{
functiona();
return 0;
}

5. 在AMD64中使用msvc编译器与机器指令用数组调用MessageBoxA(程序中需要加载User32.dll后才能运行成功)

要加载User32.dll有两种方法,

第一种为静态加载动态库,需要在程序中使用过User32.dll里的函数。

第二种为动态加载动态库,需要在调用call指令前使用LoadLibraryA加载User32.dll

  1. 将汇编代码转为机器码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
          /*
    sub rsp,28h
    xor r9,r9
    xor r8,r8
    xor rdx,rdx
    xor rcx,rcx
    mov rax,0x7FFAB222A3C0
    call rax
    add rsp,28h
    ret
    */
    // 定义机器码
    unsigned char code[] = {
    0x48,0x83,0xEC,0x28
    ,0x4D,0x31,0xC9
    ,0x4D,0x31,0xC0
    ,0x48,0x31,0xD2
    ,0x48,0x31,0xC9
    ,0x48,0xB8,0xC0,0xA3,0x22,0xB2,0xFA,0x7F
    ,0x00,0x00,0xFF,0xD0
    ,0x48,0x83,0xC4,0x28
    ,0xC3
    };


    2. 编写C语言代码

    ```c
    #include <stdio.h>
    #include <windows.h>

    void MessageM()
    {
    /*
    sub rsp,28h
    xor r9,r9
    xor r8,r8
    xor rdx,rdx
    xor rcx,rcx
    mov rax,0x7FFAB222A3C0
    call rax
    add rsp,28h
    ret
    */
    // 定义机器码
    unsigned char code[] = {
    0x48,0x83,0xEC,0x28
    ,0x4D,0x31,0xC9
    ,0x4D,0x31,0xC0
    ,0x48,0x31,0xD2
    ,0x48,0x31,0xC9
    ,0x48,0xB8,0xC0,0xA3,0x22,0xB2,0xFA,0x7F
    ,0x00,0x00,0xFF,0xD0
    ,0x48,0x83,0xC4,0x28
    ,0xC3
    };

    //更改内存属性为可读可写可执行
    DWORD dwOldProtect = 0;
    VirtualProtectEx(GetCurrentProcess(), (LPVOID)&code, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwOldProtect);
    long long (*funcPtr)() = &code;
    // 调用机器码
    long long result = funcPtr();
    printf("Result: %lld\n", result);

    }
    int LoadUser32()
    {
    HMODULE hUser32 = LoadLibraryA("User32.dll");
    if (hUser32 == NULL)
    {
    printf("加载 User32.dll 失败 (Error code: %d)\n", GetLastError());
    return -1;
    }

    return 0;

    }
    int main()
    {
    LoadUser32();
    MessageM();
    return 0;
    }

二、 分配地址来复制并执行数组中的机器码

1. 将x86汇编指令调用MessageBoxA转为机器码后分配地址来复制并执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <stdio.h>
#include <windows.h>

void MessageM() {
// 定义机器码
char code[] = {
0x6A,0x00, //push 0
0x6A,0x00, //push 0
0x6A,0x00, //push 0
0x6A,0x00, //push 0
0xB8,0x50,0xAF,0x37,0x77, //mov eax, 7737AF50h
0xFF,0xD0, //call eax
0xC3 //ret
};

// 分配可执行内存
void* exec_mem = VirtualAlloc(0, sizeof(code), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (exec_mem == NULL) {
printf("Memory allocation failed.\n");
return;
}

// 将机器码复制到分配的内存中
memcpy(exec_mem, code, sizeof(code));

// 定义函数指针
typedef int (*func_ptr)();
func_ptr func = (func_ptr)exec_mem;

// 调用机器码
int result = func();
printf("Result: %d\n", result); // 应该输出 1

// 释放内存
VirtualFree(exec_mem, 0, MEM_RELEASE);
}

int main() {
MessageM();
return 0;
}

2. 将64位汇编指令自增转为机器码后分配地址来复制并执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <windows.h>

void MessageM() {
// 定义机器码
unsigned char code[] = {
0x48, 0x31, 0xC0, // xor rax, rax
0x48, 0xFF, 0xC0, // inc rax
0xC3 // ret
};

// 分配可执行内存
void* exec_mem = VirtualAlloc(0, sizeof(code), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (exec_mem == NULL) {
printf("Memory allocation failed.\n");
return;
}

// 将机器码复制到分配的内存中
memcpy(exec_mem, code, sizeof(code));

// 定义函数指针
typedef int (*func_ptr)();
func_ptr func = (func_ptr)exec_mem;

// 调用机器码
int result = func();
printf("Result: %d\n", result); // 应该输出 1

// 释放内存
VirtualFree(exec_mem, 0, MEM_RELEASE);
}

int main() {
MessageM();
return 0;
}

3. 在AMD64中使用msvc编译器与机器指令用动态内存调用MessageBoxA(需加载模块User32.dll)

这里使用方法一,静态加载动态库User32.dll,具体为使用User32.dll中的函数MessageBoxA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <stdio.h>
#include <windows.h>

void MessageM()
{
/*

xor r9,r9
xor r8,r8
xor rdx,rdx
xor rcx,rcx
mov rax,0x7FFAB222A3C0
call rax

ret
*/
// 定义机器码
unsigned char code[] = {
0x48,0x83,0xEC,0x28
,0x4D,0x31,0xC9
,0x4D,0x31,0xC0
,0x48,0x31,0xD2
,0x48,0x31,0xC9
,0x48,0xB8,0xC0,0xA3,0x22,0xB2,0xFA,0x7F
,0x00,0x00,0xFF,0xD0
,0x48,0x83,0xC4,0x28
,0xC3
};

// 分配可执行内存
void* exec_mem = VirtualAlloc(0, sizeof(code), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (exec_mem == NULL) {
printf("Memory allocation failed.\n");
return;
}

// 将机器码复制到分配的内存中
memcpy(exec_mem, &code, sizeof(code));
long long (*funcPtr)() = exec_mem;
// 调用机器码
long long result = funcPtr();
printf("Result: %lld\n", result); // 应该输出 1
// 释放内存
VirtualFree(exec_mem, 0, MEM_RELEASE);

}

int main()
{
MessageM();
MessageBoxA(0, 0, 0, 0);
return 0;
}