[toc]

C语言修改x86内存权限使程序可以读写全局常量的值

1.在C语言中全局变量的可读不可写

  1. 读取全局常量的值,成功执行

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

    int c_Var = 0x400000;

    int main(int argc, char* argv[])
    {
    printf("%d\n", c_Var);
    __asm
    {
    mov dword ptr[c_Var], 634
    }
    printf("%d\n", c_Var);
    return 0;
    }
  2. 写入全局只读变量的值,程序崩溃。

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

    const int c_Var = 0x400000;

    int main(int argc, char* argv[])
    {

    printf("%d\n", c_Var);
    __asm
    {
    mov dword ptr[c_Var], 634
    }
    printf("%d\n", c_Var);
    return 0;
    }

2.使用VirtualProtect()函数修改自身内存属性

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

const int c_Var = 0x400000;

int main(int argc, char* argv[])
{
printf("%d\n", c_Var);
DWORD dwOldProtect = 0;
VirtualProtect((LPVOID)&c_Var, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwOldProtect);
__asm
{
mov dword ptr[c_Var], 634
}
printf("%d\n", c_Var);
return 0;
}

运行成功

3.使用VirtualProtectEx()函数修改自身内存属性

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

const int c_Var = 0x400000;

int main(int argc, char* argv[])
{
printf("%d\n", c_Var);
DWORD dwOldProtect = 0;
VirtualProtectEx(GetCurrentProcess(), (LPVOID)&c_Var, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwOldProtect);
__asm
{
mov dword ptr[c_Var], 634
}
printf("%d\n", c_Var);
return 0;
}

4.使用VirtualProtect()更改程序自身函数内存地址页属性后改变函数指令

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
#include <windows.h>
#include <stdio.h>

void Demo()
{
}
int main() {
DWORD oldProtect;
// 假设我们要修改某个内存区域的保护属性
LPVOID address = (LPVOID)&Demo; // 示例地址
printf("%p\n", Demo);
unsigned char data[] = { 0xC3,0xC3};

SIZE_T size = sizeof(data); // 示例大小
if (VirtualProtect(address, size, PAGE_EXECUTE_READWRITE, &oldProtect))
{
printf("Memory protection changed successfully.\n");
memcpy(address, data, sizeof(data));
}
else
{
printf("Failed to change memory protection. Error: %lu\n", GetLastError());
}
VirtualProtect(address, size, oldProtect, &oldProtect);

Demo();
getchar();
return 0;
}

5.msvc编译器64位中不支持内连汇编,可以更换其他编译器例如llvm或者intel。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <Windows.h>
const int c_Var = 0x400000;

int main(int argc, char* argv[])
{
printf("Before: %d\n", c_Var);
DWORD dwOldProtect = 0;
VirtualProtect((LPVOID)&c_Var, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwOldProtect);
__asm {
mov dword ptr[c_Var], 634
}
printf("%d\n", c_Var);
//此时反汇编查看c_Var变量可以看到值已经改变了,但是clang_cl编译器不知道,打印的还是旧值
// 避免优化:强制编译器重新读 c_Var
//最简单的方法是使用指针访问而不是直接使用变量/**/
const int* p = &c_Var;
printf("After: %d\n", *p);

return 0;
}

C语言在windows中跨进程修改内存属性使其可读可写可执行

1. 准备Message程序,里面有可读不可写的全局常量,保持运行

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

const int c_Var = 0x400000;
int main(int argc, char** argv)
{
label:
printf("c_Var i vulue is %d\n", c_Var);
printf("c_Var i address is 0x%p\n", &c_Var);
printf("current Pid is %d\n", GetCurrentProcessId());
getchar();
goto label;
return 0;
}

运行成功

2.跨进程编写C语言代码修改内存属性后修改全局常量

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


int main(int argc, char* argv[])
{
DWORD dwProcessId = 116348;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
DWORD lpBaseAddr = 0x00417B30;//0x0019FEDC is address
DWORD buffer = 2080;//send for write data
SIZE_T nSize = sizeof(buffer);//read 4 bytes data
SIZE_T* writeLength = malloc(sizeof(SIZE_T));//output value is actully readed data size
DWORD dwOldProtect = 0;
VirtualProtectEx(hProcess, (LPVOID)lpBaseAddr, sizeof(DWORD), PAGE_EXECUTE_READWRITE, &dwOldProtect);
BOOL status=WriteProcessMemory(hProcess, lpBaseAddr, &buffer, nSize, writeLength);
if (status != TRUE)return GetLastError();
ReadProcessMemory(hProcess, lpBaseAddr, &buffer, nSize, writeLength);
printf("Write address 0x%p data is %d\n", lpBaseAddr, buffer);
printf("Write data length is %d\n", *writeLength);
CloseHandle(hProcess);
return 0;
}

运行成功