红联Linux门户
Linux帮助

程序段错误 Segmentation fault

发布时间:2010-11-14 11:04:28来源:红联作者:vfdff
[code]#include
#include
#include
#include
#include
#include

#define MAX_FUNC_NUM 64 // 用于记录打桩函数同时使用的最大项
#define FLATJMPCODE_LENGTH 5 // 绝对跳转指令长度
#define TRUE 0
#define FALSE 1
typedef unsigned char BYTE;
typedef unsigned long ULONG;
typedef void *LPVOID;
typedef ULONG *FUNCPTR; // 定义一个函数指针类型

// 用于记录函数指针地址的结构体
typedef class FuncList {
public:
FUNCPTR newFuncList;
FUNCPTR oldFuncList;
BYTE oldFuncInstruct[FLATJMPCODE_LENGTH];
} FuncList_t;

static FuncList_t g_FuncList[MAX_FUNC_NUM] = { {NULL} }; // 用于记录函数指针地址

/*
函数名称:ChangeProtection
功能: 完成函数地址空间的读写权限的修改
参数:
[in] ulAddr,待修改读写模式内存的开始地址
[in] ulLength,待修改读写模式内存的长度
[in] ulMode, 设置的读写权限值

返回值:成功返回TRUE,失败返回FALSE
说明: mprotect函数是专门设置虚拟内存区域属性的函数
*/
unsigned int ChangeProtection(const unsigned int ulAddr, const unsigned int ulLength, const unsigned int ulMode )
{
unsigned int ulLastPageEnd;
unsigned int ulFirstPageStart;

/* Find the start address of the page to which the adress belongs to */
ulFirstPageStart = ulAddr - (ulAddr % 4096);

ulLastPageEnd = ulAddr + ulLength;
ulLastPageEnd += 4096 - (ulLastPageEnd % 4096);

if (TRUE != mprotect((void*)ulFirstPageStart, ulLastPageEnd - ulFirstPageStart, ulMode ))
{
return FALSE;
}

return TRUE;
}

unsigned int ModProtectMemContent(unsigned long* pBaseAddress, \
const BYTE* pucInstruContent, unsigned long ulInstruLen)
{
if (ChangeProtection((const unsigned int)pBaseAddress, ulInstruLen, PROT_WRITE | PROT_READ | PROT_EXEC) == FALSE)
{
return FALSE;
}

// 修改老函数入口处的指令,用上面准备的跳转指令修改
(void)memcpy(pBaseAddress, pucInstruContent, ulInstruLen);

if (ChangeProtection((const unsigned int)pBaseAddress, ulInstruLen, PROT_READ | PROT_EXEC) == FALSE)
{
return FALSE;
}
return TRUE;
}

/*
函数名称:ReadProcessMemExt
功能: 完成获取进程内容的功能,是对ReadProcessMemory的扩展
参数:
[in] pBaseAddress,待写内存开始地址
[in] ulInstruLen, 要读取的内容的长度
[out] pucInstruContent,保存读到的内容
返回值:成功返回TRUE,失败返回FALSE
*/
unsigned int ReadProcessMemExt(unsigned long* pBaseAddress, \
unsigned long ulInstruLen, BYTE* pucInstruContent)
{
if (ChangeProtection((const unsigned int)pBaseAddress, ulInstruLen, PROT_WRITE | PROT_READ | PROT_EXEC) == FALSE)
{
return FALSE;
}

// 获取指定内存的内容
(void)memcpy(pucInstruContent, pBaseAddress, ulInstruLen);

if (ChangeProtection((const unsigned int)pBaseAddress, ulInstruLen, PROT_READ | PROT_EXEC) == FALSE)
{
return FALSE;
}

return TRUE;
}

// 利用void*来传递参数,使通过g++编译
int ContainAdd(void *pOldFunc, void *pNewFunc)
{
int i;
int iInstruLen, iTmpLen;
unsigned long dwNewInstructOffset;
unsigned long dwOldJumpOffset;
unsigned long dwTmpJumpOffset;
BYTE aucSaveInstru[30];
BYTE aBuf[10];

//printf("Input(0) pOldFunc = 0x%x, pNewFunc = 0x%x!\n", pOldFunc, pNewFunc);
//printf("Input(1) pOldFunc = 0x%x, pNewFunc = 0x%x!\n", &pOldFunc, &pNewFunc);
//printf("Input(2) pOldFunc = 0x%x, pNewFunc = 0x%x!\n", ((unsigned long*)pOldFunc+1), ((unsigned long*)pNewFunc+1));
//printf("Input(3) pOldFunc = 0x%x, pNewFunc = 0x%x!\n", ((unsigned long*)pOldFunc+2), ((unsigned long*)pNewFunc+2));
// 查找未使用的空的结构体
for (i=0; i {
if(NULL == g_FuncList[i].oldFuncList) // 找到了未使用的空间
break;
} // end for i
if (MAX_FUNC_NUM <= i)
{
printf("The number of stub function if too many!\n");
return FALSE;
}

// 获取原函数开始的一段指令

// 说明:由于函数地址在保护区域,不能用普通的修改内存值的方式实现,
// 只能通过系统函数,来改变某个进程的内存内容方式实现
ReadProcessMemExt((unsigned long*)pOldFunc, FLATJMPCODE_LENGTH, aucSaveInstru);
// 先得到原函数调用地址的跳转偏移,为下面计算相对偏移做准备
// 将新函数指针和原函数调用地址保存到列表中
g_FuncList[i].oldFuncList = (FUNCPTR)pOldFunc;
g_FuncList[i].newFuncList = (FUNCPTR)pNewFunc;
memcpy(g_FuncList[i].oldFuncInstruct, aucSaveInstru, FLATJMPCODE_LENGTH);

// 得到新函数指令跳转值
dwNewInstructOffset = ((ULONG)pNewFunc - (ULONG)pOldFunc - FLATJMPCODE_LENGTH);
// 修改老函数入口处的指令,用跳转指令替代
// 准备要填入的指令机器码,需要修改5个字节内容
aBuf[0] = 0xE9; // 0XE9为相对跳转指令的机器码,具体可以参考intel手册
*(ULONG*)((BYTE*)aBuf + 1) = dwNewInstructOffset;
if ( FALSE == ModProtectMemContent((ULONG*)pOldFunc, aBuf, FLATJMPCODE_LENGTH) )
{
printf("\r\nModProtectMemContent fail!\n");
return FALSE;
}

return TRUE;
}

//////////////////////////////////////////////////////////
void exit_stub(int status)
{
char a[]="hello world";
printf("exit_stub %d %p, %p\n", status, &status, exit_stub);
//exit(1);
return ;
}
//////////////////////////////////////////////////////////////////////

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

printf("\ntest generic function 11\n");
ContainAdd((void*)(exit), (void*)(exit_stub));
printf("Input(0) pOldFunc = 0x%x, pNewFunc = 0x%x!\n", exit, exit_stub);
exit_stub(1);
exit(1);

printf("\ntest generic function 31\n");

return 0;
}[/code]使用gcc test.c -o test 编译
使用./test运行时发生断错误,提示:Program received signal SIGSEGV, Segmentation fault.

麻烦大家帮忙一起定位下问题,谢谢!
文章评论

共有 5 条评论

  1. superherogood 于 2011-02-09 16:33:24发表:

    为啥不用gdb调试跟踪啊。

  2. vfdff 于 2010-11-15 23:29:15发表:

    引用:
    C里面没有public这东西,C++才有。
    用g++编译看下
    alick 发表于 2010-11-14 13:56


    g++ hook.c -o test -g -static 如此编译执行还是不行

  3. vfdff 于 2010-11-15 23:28:14发表:

    应该不是这个问题,如果关键字不认识 一定抱语法错误

  4. sloepx 于 2010-11-14 15:02:47发表:

    帮顶上

  5. alick 于 2010-11-14 13:56:04发表:

    C里面没有public这东西,C++才有。
    用g++编译看下