得到函数的机器码,用函数指针执行的问题

时间:2021-09-16 17:09:50
大概的意思就是:写一个函数,然后反汇编,用函数指针运行这个函数。
我的代码如下:

#include <stdio.h>
#define MAX 1024
//typedef void (*fp)(int *,int *);
void swap(int *a, int *b){
int tmp = *a;
*a = *b;
*b = tmp;
}

int main(int argc ,char *argv[]){
unsigned char machineCode[MAX] = {
0x55,
0x89,0xe5,
0x83,0xec,0x10,
0x8b,0x45,0x08,
0x8b,0x00,
0x89,0x45,0xfc,
0x8b,0x45,0x0c,
0x8b,0x10,
0x8b,0x45,0x08,
0x89,0x10,
0x8b,0x45,0x0c,
0x8b,0x55,0xfc,
0x89,0x10,
0xc9,
0xc3
};

void (* fp)(int *,int *);

fp = (void (*)(int *,int *))machineCode;

int a = 10,b = 20;
printf("%d\t%d\n",a,b);

swap(&a,&b);
printf("%d\t%d\n",a,b);

(*fp)(&a,&b);
printf("%d\t%d\n",a,b);

return 0;
}

编译没错,运行时出现错误Segmentation fault  (core dumped)
请各位大神帮忙指出我的错误,谢谢。

8 个解决方案

#1


指针变量占用的字节数是固定的,比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针,那么也应该是4个字节才对。
正确的做法是,将函数的地址赋值给fp,即在栈上给你要执行的函数的栈地址赋值给fp.

#2


引用 1 楼 cfjtaishan 的回复:
指针变量占用的字节数是固定的,比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针,那么也应该是4个字节才对。
正确的做法是,将函数的地址赋值给fp,即在栈上给你要执行的函数的栈地址赋值给fp.

那个数组是我用objdump反汇编swap函数得到的机器码,我想用那个函数指针执行数组里面的机器码,请问这种情况下需要改什么呢?unsigned char改为unsigned int?我改过了,还是一样的错误……

#3


引用 2 楼 Wang_926498 的回复:
Quote: 引用 1 楼 cfjtaishan 的回复:

指针变量占用的字节数是固定的,比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针,那么也应该是4个字节才对。
正确的做法是,将函数的地址赋值给fp,即在栈上给你要执行的函数的栈地址赋值给fp.

那个数组是我用objdump反汇编swap函数得到的机器码,我想用那个函数指针执行数组里面的机器码,请问这种情况下需要改什么呢?unsigned char改为unsigned int?我改过了,还是一样的错误……

指向函数不会像执行输出数组那么简单吧。
 fp = (void (*)(int *,int *))machineCode;

这句就是将数组的前4个字节的值赋值给了fp。

#4


引用 3 楼 cfjtaishan 的回复:
Quote: 引用 2 楼 Wang_926498 的回复:

Quote: 引用 1 楼 cfjtaishan 的回复:

指针变量占用的字节数是固定的,比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针,那么也应该是4个字节才对。
正确的做法是,将函数的地址赋值给fp,即在栈上给你要执行的函数的栈地址赋值给fp.

那个数组是我用objdump反汇编swap函数得到的机器码,我想用那个函数指针执行数组里面的机器码,请问这种情况下需要改什么呢?unsigned char改为unsigned int?我改过了,还是一样的错误……

指向函数不会像执行输出数组那么简单吧。
 fp = (void (*)(int *,int *))machineCode;

这句就是将数组的前4个字节的值赋值给了fp。

我看书发现了错误,machineCode位于数据段,没有执行权限,需要用mmap分配空间,然后把机器码复制过去,这样便能够执行了,并不是您提到的格式问题,谢谢您的回答。

#5


仅供参考:
/*
    Application:    Code Injection in Explorer
    Author:     @_RT
    Compiled on:    Feb 2014
    URL:http://www.codeproject.com/Tips/732044/Code-Injection-2

    We will see the different steps involved to perform a code injection into an already running process.

    Following are the quick steps through the process of injection.
    1.Get the API addresses that you will be calling from the injected code.
    2.Prepare shell code of your function that you want to get executed from the injected process.
    3.Get the process ID of the running process that you wish to inject into by enumerating through the
      list of processes or by finding the process's window (in case it's a GUI application) by class name or title.
    4.Open the process using its Pid with All Access rights.
    5.Allocate different memory spaces in the process that you are going to inject to with desired access
      rights for holding different segments of your shell code.
        Code part (executable instructions)
        Data part (strings, function parameters, etc.)
    6.Write the allocated memories with the respective values (code and data).
    7.Call CreateRemoteThread API and pass to it the start of allocated memory address where you have
      written your shell code from the process we are injecting.
*/

#include <windows.h>
#pragma comment(lib,"user32.lib")

LPVOID addr;
LPVOID addr2;

BOOL InjectExecutable(DWORD dwPid,LPVOID si,LPVOID pi,int sisize,int pisize)
{
    LPVOID hNewModule;
    HANDLE hProcess;
    CHAR S[]    = { "C:\\Windows\\system32\\notepad.exe" };
    BYTE byt[]  = {0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x01, 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0x68};
                 //push  0   , push     0, push     0, push     1, push     0, push     0, push     0, push 0xXXXXXXXX
    BYTE byt2[] = {0xE8};//call 0xXXXXXXXX
    BYTE byt3[] = {0x68};//push 0xXXXXXXXX

    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
    if (hProcess == NULL)
    {
        return FALSE;
    }

    LPVOID staddr = VirtualAllocEx(hProcess, NULL, sizeof(S), MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, staddr, S, sizeof(S), NULL);
    LPVOID fnaddr = VirtualAllocEx(hProcess, NULL, 4, MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, fnaddr, pi, sisize, NULL);
    LPVOID fnaddr2 = VirtualAllocEx(hProcess, NULL, 4, MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, fnaddr2, si, pisize, NULL);

    hNewModule = VirtualAllocEx(hProcess, NULL, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (hNewModule == NULL)
    {
        return FALSE;
    }
    LPTHREAD_START_ROUTINE strtaddr = (LPTHREAD_START_ROUTINE)hNewModule;

    WriteProcessMemory(hProcess, hNewModule, byt3, sizeof(byt3), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(byt3));
    WriteProcessMemory(hProcess, hNewModule, &fnaddr, sizeof(fnaddr), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(fnaddr));                    // push &pi ;lpProcessInformation
    WriteProcessMemory(hProcess, hNewModule, byt3, sizeof(byt3), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(byt3));
    WriteProcessMemory(hProcess, hNewModule, &fnaddr2, sizeof(fnaddr2), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(fnaddr2));                   // push &si ;lpStartupInfo
    WriteProcessMemory(hProcess, hNewModule, byt, sizeof(byt), NULL);           // push 0 , push 0, push 0, push 1, push 0, push 0, push 0, push 0xXXXXXXXX==&S[0];"C:\\Windows\\system32\\notepad.exe"
    hNewModule = (LPVOID)((int)hNewModule + sizeof(byt));                       // lpCurrentDirectory,lpEnvironment,dwCreationFlags,bInheritHandles,lpThreadAttributes,lpProcessAttributes,lpCommandLine,lpApplicationName
    WriteProcessMemory(hProcess, hNewModule, &staddr, sizeof(staddr), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(staddr));
    WriteProcessMemory(hProcess, hNewModule, byt2, sizeof(byt2), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(byt2));                      // call CreateProcessA
    addr = (LPVOID)((int)addr - ((int)hNewModule + 4));
    WriteProcessMemory(hProcess, hNewModule, &addr, sizeof(addr), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(addr));
    WriteProcessMemory(hProcess, hNewModule, byt, 2, NULL);
    hNewModule = (LPVOID)((int)hNewModule + 2);                                 // push 0 ;DWORD dwExitCode   // exit code for this thread
    WriteProcessMemory(hProcess, hNewModule, byt2, sizeof(byt2), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(byt2));                      // call ExitThread
    addr2 = (LPVOID)((int)addr2 - ((int)hNewModule + 4));
    WriteProcessMemory(hProcess, hNewModule, &addr2, sizeof(addr2), NULL);

    CreateRemoteThread(hProcess, 0, 0, strtaddr, NULL, 0, NULL);
    return TRUE;
}

int main()
{
    _STARTUPINFOA si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    DWORD dwPid;
    HMODULE ldlib = LoadLibraryA("Kernel32.dll");
    addr = GetProcAddress(ldlib, "CreateProcessA");
    addr2 = GetProcAddress(ldlib, "ExitThread");
    HWND hWnd1=FindWindow(NULL, "Program Manager");
    if (NULL==hWnd1) {
        return 1;
    }
    GetWindowThreadProcessId(hWnd1, &dwPid);

    InjectExecutable(dwPid,&si,&pi,sizeof(si),sizeof(pi));

    return 0;
}

#6


引用 4 楼 Wang_926498 的回复:
Quote: 引用 3 楼 cfjtaishan 的回复:

Quote: 引用 2 楼 Wang_926498 的回复:

Quote: 引用 1 楼 cfjtaishan 的回复:

指针变量占用的字节数是固定的,比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针,那么也应该是4个字节才对。
正确的做法是,将函数的地址赋值给fp,即在栈上给你要执行的函数的栈地址赋值给fp.

那个数组是我用objdump反汇编swap函数得到的机器码,我想用那个函数指针执行数组里面的机器码,请问这种情况下需要改什么呢?unsigned char改为unsigned int?我改过了,还是一样的错误……

指向函数不会像执行输出数组那么简单吧。
 fp = (void (*)(int *,int *))machineCode;

这句就是将数组的前4个字节的值赋值给了fp。

我看书发现了错误,machineCode位于数据段,没有执行权限,需要用mmap分配空间,然后把机器码复制过去,这样便能够执行了,并不是您提到的格式问题,谢谢您的回答。

直接把数组以强制类型转换的形式赋值给函数指针变量,这样就是类型就是不对的。
函数是在堆栈上执行的,你是用mmap是不行的,我的理解mmap是申请共享内存,并且这个内存是在内核空间里申请的。
建议这个问题最好看一下,编译,加载的过程。

#7


我认为是不可以的,你用mmap试一下,如果能够实现,那我也学习了。

#8


现在的系统下, 一般都开了 DEP, 栈啊, 数据段啊啥的通常都是不可运行的, 你 mprotect  改下内存保护应该就可以了。

#1


指针变量占用的字节数是固定的,比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针,那么也应该是4个字节才对。
正确的做法是,将函数的地址赋值给fp,即在栈上给你要执行的函数的栈地址赋值给fp.

#2


引用 1 楼 cfjtaishan 的回复:
指针变量占用的字节数是固定的,比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针,那么也应该是4个字节才对。
正确的做法是,将函数的地址赋值给fp,即在栈上给你要执行的函数的栈地址赋值给fp.

那个数组是我用objdump反汇编swap函数得到的机器码,我想用那个函数指针执行数组里面的机器码,请问这种情况下需要改什么呢?unsigned char改为unsigned int?我改过了,还是一样的错误……

#3


引用 2 楼 Wang_926498 的回复:
Quote: 引用 1 楼 cfjtaishan 的回复:

指针变量占用的字节数是固定的,比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针,那么也应该是4个字节才对。
正确的做法是,将函数的地址赋值给fp,即在栈上给你要执行的函数的栈地址赋值给fp.

那个数组是我用objdump反汇编swap函数得到的机器码,我想用那个函数指针执行数组里面的机器码,请问这种情况下需要改什么呢?unsigned char改为unsigned int?我改过了,还是一样的错误……

指向函数不会像执行输出数组那么简单吧。
 fp = (void (*)(int *,int *))machineCode;

这句就是将数组的前4个字节的值赋值给了fp。

#4


引用 3 楼 cfjtaishan 的回复:
Quote: 引用 2 楼 Wang_926498 的回复:

Quote: 引用 1 楼 cfjtaishan 的回复:

指针变量占用的字节数是固定的,比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针,那么也应该是4个字节才对。
正确的做法是,将函数的地址赋值给fp,即在栈上给你要执行的函数的栈地址赋值给fp.

那个数组是我用objdump反汇编swap函数得到的机器码,我想用那个函数指针执行数组里面的机器码,请问这种情况下需要改什么呢?unsigned char改为unsigned int?我改过了,还是一样的错误……

指向函数不会像执行输出数组那么简单吧。
 fp = (void (*)(int *,int *))machineCode;

这句就是将数组的前4个字节的值赋值给了fp。

我看书发现了错误,machineCode位于数据段,没有执行权限,需要用mmap分配空间,然后把机器码复制过去,这样便能够执行了,并不是您提到的格式问题,谢谢您的回答。

#5


仅供参考:
/*
    Application:    Code Injection in Explorer
    Author:     @_RT
    Compiled on:    Feb 2014
    URL:http://www.codeproject.com/Tips/732044/Code-Injection-2

    We will see the different steps involved to perform a code injection into an already running process.

    Following are the quick steps through the process of injection.
    1.Get the API addresses that you will be calling from the injected code.
    2.Prepare shell code of your function that you want to get executed from the injected process.
    3.Get the process ID of the running process that you wish to inject into by enumerating through the
      list of processes or by finding the process's window (in case it's a GUI application) by class name or title.
    4.Open the process using its Pid with All Access rights.
    5.Allocate different memory spaces in the process that you are going to inject to with desired access
      rights for holding different segments of your shell code.
        Code part (executable instructions)
        Data part (strings, function parameters, etc.)
    6.Write the allocated memories with the respective values (code and data).
    7.Call CreateRemoteThread API and pass to it the start of allocated memory address where you have
      written your shell code from the process we are injecting.
*/

#include <windows.h>
#pragma comment(lib,"user32.lib")

LPVOID addr;
LPVOID addr2;

BOOL InjectExecutable(DWORD dwPid,LPVOID si,LPVOID pi,int sisize,int pisize)
{
    LPVOID hNewModule;
    HANDLE hProcess;
    CHAR S[]    = { "C:\\Windows\\system32\\notepad.exe" };
    BYTE byt[]  = {0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x01, 0x6A, 0x00, 0x6A, 0x00, 0x6A, 0x00, 0x68};
                 //push  0   , push     0, push     0, push     1, push     0, push     0, push     0, push 0xXXXXXXXX
    BYTE byt2[] = {0xE8};//call 0xXXXXXXXX
    BYTE byt3[] = {0x68};//push 0xXXXXXXXX

    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
    if (hProcess == NULL)
    {
        return FALSE;
    }

    LPVOID staddr = VirtualAllocEx(hProcess, NULL, sizeof(S), MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, staddr, S, sizeof(S), NULL);
    LPVOID fnaddr = VirtualAllocEx(hProcess, NULL, 4, MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, fnaddr, pi, sisize, NULL);
    LPVOID fnaddr2 = VirtualAllocEx(hProcess, NULL, 4, MEM_COMMIT, PAGE_READWRITE);
    WriteProcessMemory(hProcess, fnaddr2, si, pisize, NULL);

    hNewModule = VirtualAllocEx(hProcess, NULL, 100, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (hNewModule == NULL)
    {
        return FALSE;
    }
    LPTHREAD_START_ROUTINE strtaddr = (LPTHREAD_START_ROUTINE)hNewModule;

    WriteProcessMemory(hProcess, hNewModule, byt3, sizeof(byt3), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(byt3));
    WriteProcessMemory(hProcess, hNewModule, &fnaddr, sizeof(fnaddr), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(fnaddr));                    // push &pi ;lpProcessInformation
    WriteProcessMemory(hProcess, hNewModule, byt3, sizeof(byt3), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(byt3));
    WriteProcessMemory(hProcess, hNewModule, &fnaddr2, sizeof(fnaddr2), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(fnaddr2));                   // push &si ;lpStartupInfo
    WriteProcessMemory(hProcess, hNewModule, byt, sizeof(byt), NULL);           // push 0 , push 0, push 0, push 1, push 0, push 0, push 0, push 0xXXXXXXXX==&S[0];"C:\\Windows\\system32\\notepad.exe"
    hNewModule = (LPVOID)((int)hNewModule + sizeof(byt));                       // lpCurrentDirectory,lpEnvironment,dwCreationFlags,bInheritHandles,lpThreadAttributes,lpProcessAttributes,lpCommandLine,lpApplicationName
    WriteProcessMemory(hProcess, hNewModule, &staddr, sizeof(staddr), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(staddr));
    WriteProcessMemory(hProcess, hNewModule, byt2, sizeof(byt2), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(byt2));                      // call CreateProcessA
    addr = (LPVOID)((int)addr - ((int)hNewModule + 4));
    WriteProcessMemory(hProcess, hNewModule, &addr, sizeof(addr), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(addr));
    WriteProcessMemory(hProcess, hNewModule, byt, 2, NULL);
    hNewModule = (LPVOID)((int)hNewModule + 2);                                 // push 0 ;DWORD dwExitCode   // exit code for this thread
    WriteProcessMemory(hProcess, hNewModule, byt2, sizeof(byt2), NULL);
    hNewModule = (LPVOID)((int)hNewModule + sizeof(byt2));                      // call ExitThread
    addr2 = (LPVOID)((int)addr2 - ((int)hNewModule + 4));
    WriteProcessMemory(hProcess, hNewModule, &addr2, sizeof(addr2), NULL);

    CreateRemoteThread(hProcess, 0, 0, strtaddr, NULL, 0, NULL);
    return TRUE;
}

int main()
{
    _STARTUPINFOA si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    DWORD dwPid;
    HMODULE ldlib = LoadLibraryA("Kernel32.dll");
    addr = GetProcAddress(ldlib, "CreateProcessA");
    addr2 = GetProcAddress(ldlib, "ExitThread");
    HWND hWnd1=FindWindow(NULL, "Program Manager");
    if (NULL==hWnd1) {
        return 1;
    }
    GetWindowThreadProcessId(hWnd1, &dwPid);

    InjectExecutable(dwPid,&si,&pi,sizeof(si),sizeof(pi));

    return 0;
}

#6


引用 4 楼 Wang_926498 的回复:
Quote: 引用 3 楼 cfjtaishan 的回复:

Quote: 引用 2 楼 Wang_926498 的回复:

Quote: 引用 1 楼 cfjtaishan 的回复:

指针变量占用的字节数是固定的,比如32为系统上指针变量就是占用4个字节。 如果将machineCode强制转换为函数指针,那么也应该是4个字节才对。
正确的做法是,将函数的地址赋值给fp,即在栈上给你要执行的函数的栈地址赋值给fp.

那个数组是我用objdump反汇编swap函数得到的机器码,我想用那个函数指针执行数组里面的机器码,请问这种情况下需要改什么呢?unsigned char改为unsigned int?我改过了,还是一样的错误……

指向函数不会像执行输出数组那么简单吧。
 fp = (void (*)(int *,int *))machineCode;

这句就是将数组的前4个字节的值赋值给了fp。

我看书发现了错误,machineCode位于数据段,没有执行权限,需要用mmap分配空间,然后把机器码复制过去,这样便能够执行了,并不是您提到的格式问题,谢谢您的回答。

直接把数组以强制类型转换的形式赋值给函数指针变量,这样就是类型就是不对的。
函数是在堆栈上执行的,你是用mmap是不行的,我的理解mmap是申请共享内存,并且这个内存是在内核空间里申请的。
建议这个问题最好看一下,编译,加载的过程。

#7


我认为是不可以的,你用mmap试一下,如果能够实现,那我也学习了。

#8


现在的系统下, 一般都开了 DEP, 栈啊, 数据段啊啥的通常都是不可运行的, 你 mprotect  改下内存保护应该就可以了。