欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]OdScript+VC 练习还原重定位表

[原创]OdScript+VC 练习还原重定位表

用VC2010编译出来的EXE程序跟DLL很像,在PE文件里的基址一般写着0X400000,但是一般不会被加载到这个位置。这就意味着,如果加壳工具去除了EXE程序的原始重定位表,我们似乎只能用两种方法来处理壳:1.在壳代码中强制它以0X400000为重定位基址,然后DUMP 2.像处理DLL一样修复它的重定位表。本文以UPX加EXE为例试验了第二种方法,修复EXE的重定位与修复DLL的重定位原理差不多,坛上帖子多,我就不废话了。
大致操作过程如下:
1.使用的ESP定律迅速找到OEP 2.找到OEP以后进入原程序的代码,找几个需要重定位的地址,下内存断点,中断两三次后会发现类似下面这样的代码,拦截ebx,保存起来后处理一下即可得到重定位表。
add eax,esi
mov [ebx],eax
详细操作见OD代码:

var bp1rva=10546 

var pcurrmem_ori=0

var pcurrmem

var membase=0

var memsize=2000

var hdaddr=0

msgyn "是否要执行本脚本?"

cmp 0,$RESULT

jnz next

next:

mov memsize,2000

alloc memsize	//分配内存用作重定位表的修复

mov pcurrmem,$RESULT

mov pcurrmem_ori,pcurrmem

log pcurrmem

gmemi eip,MEMORYOWNER

mov membase,$RESULT //获取当前加载基址

mov bp1rva,10546

add bp1rva,membase

bp bp1rva //在这个地址下断

//ESP定律

sti

mov hdaddr,esp

log hdaddr

bphws hdaddr,"r"

run

eob manytimes

manytimes:

//会先停在bp1

cmp eip,bp1rva

jnz maybetheend

mov [pcurrmem],ebx //保存即可

add pcurrmem,4//指针加4

run

maybetheend:

dm pcurrmem_ori,memsize,"d:\desktop\reloc.hex"

bphwc hdaddr

脚本运行完后的文件,有一个明显的跳转,那儿就是OEP了。
DUMP下修复一下引入表:

处理过后的文件:

如果是以前,处理到这儿已经OK。但是由于它可能加载到别的基址上去,这肯定会导致程序崩溃的。
现在可以使用一些小工具处理一下,让EXE在固定的基址启动,(这是上述提到的方法1)如:

看看dump下来的程序的重定位表:

看这数量基本就可以猜出这不是原程序的引入表了。这是upx外壳的重定位表。
我们需要重建这个。
上述代码处理完后的重定位文件的内容大致如下(其实可以在就在OD脚本里处理的,只是个人感觉比较麻烦,于是转到VC里处理):

写个VC小程序处理一下:(需要我自己的开发库,看看代码即可无法编译的,嘿嘿,除非你愿意写把所有函数和结构都补全)
char* pefile="133_.exe";

char* relocfile="reloc.hex";

char* deal_relocfile="dealed_reloc.hex";

DWORD currbase=0x1330000;

//将数值存储到对应的数组中

void log(preloc_tbl arr[],PDWORD pval)

{

	dwst dwval;

	memset(&dwval,0,sizeof(dwval));

	memcpy(&dwval,pval,sizeof(dwval));

	if(dwval.high4>NUM)

	{

		showdbg("并不是只有1000-f000这16种副基址");

		return;

	}

	if(dwval.high4==0)

	{

		showdbg("文件读入了异常数据,请确认");

	}

	wst wstitem;

	memset(&wstitem,0,sizeof(wstitem));

	wstitem.low12=dwval.low12;

	wstitem.high4=RELOC_SIGN;

	preloc_tbl ptmp=arr[dwval.high4-1];

	memcpy((ptmp->witem)+ptmp->dwblock,&wstitem,sizeof(wstitem));

	ptmp->dwblock++;

}

void makenewreloc(preloc_tbl arr[],PBYTE& finalmem,DWORD& finalmemsize)

{

	struct

	{

		PBYTE pmem;

		DWORD memsize;

	} finalpart[NUM]={0};

	DWORD dwTotalSize=0;

	DWORD dwtmpsize;

	for(int i=0;i<NUM;i++)

	{

		if(arr[i]==NULL)

			break;//可以确定这已经是最后的一组了

		if(arr[i]->dwblock==0)

			continue;//没有纪录的组

		dwtmpsize=(arr[i]->dwblock)*2+8+2;//项的数目(word)*2+头8个字符+2个结束符

		dwTotalSize+=dwtmpsize;

		finalpart[i].memsize=dwtmpsize;

		finalpart[i].pmem=BMD_AllocMem(dwtmpsize);

		DWORD dwtmptmp=(i+1)*0x1000;

		memcpy(finalpart[i].pmem+0,&dwtmptmp,sizeof(dwtmptmp));

		memcpy(finalpart[i].pmem+4,&dwtmpsize,sizeof(dwtmpsize));

		memcpy(finalpart[i].pmem+8,arr[i]->witem,dwtmpsize-8);	

	}

	finalmemsize=dwTotalSize;

	finalmem=BMD_AllocMem(finalmemsize);

	DWORD pcurr=0;

	for(int i=0;i<NUM;i++)

	{

		if(finalpart[i].pmem==NULL)

			continue;

		memcpy(finalmem+pcurr,finalpart[i].pmem,finalpart[i].memsize);

		pcurr+=finalpart[i].memsize;

	}

	//清理内存

	for(int i=0;i<NUM;i++)

	{

		if(finalpart[i].pmem!=NULL)

			BMD_FreeMem(finalpart[i].pmem);

	}

}

void main()

{

	DWORD filesize;

	PBYTE mem;

	if(BMD_FAIL==BMD_ReadFile(relocfile,&mem,&filesize))

	{

		showdbg("read fail");

		goto fail;

	}

	//建立分别用于存储各个基址的重定位数组

	preloc_tbl arr_reloc_tbl[NUM]={0};

	for(int i=0;i<NUM;i++)

	{

		arr_reloc_tbl[i]=(preloc_tbl)BMD_AllocMem(sizeof(reloc_tbl));

		arr_reloc_tbl[i]->dwmembase=(i+1)*0x1000;

		arr_reloc_tbl[i]->dwblock=0;

		arr_reloc_tbl[i]->witem=(WORD*)BMD_AllocMem(filesize);

	}

	//处理文件在外部大循环指针

	PDWORD pdw=(PDWORD)mem;

	while(*pdw!=0)

	{

		//主循环处理

		log(arr_reloc_tbl,pdw);

		pdw++;

	}

	//最终汇总

	PBYTE finalmem;

	DWORD finalmemsize;

	makenewreloc(arr_reloc_tbl,finalmem,finalmemsize);

	if(BMD_SUCC==BMD_WriteFile(deal_relocfile,finalmem,finalmemsize))

	{

		MessageBoxA(0,deal_relocfile,"成功重建输入表",0);

	}

	//异常处理

fail:

	if(mem!=NULL)

		BMD_FreeMem(mem);

	for(int i=0;i<NUM;i++)

	{

		if(arr_reloc_tbl[i]!=NULL)

			BMD_FreeMem(arr_reloc_tbl[i]);

		if(arr_reloc_tbl[i]->witem!=NULL)

			BMD_FreeMem(arr_reloc_tbl[i]->witem);

	}

	if(finalmem!=NULL)

		BMD_FreeMem(finalmem);

	return;

}

最后一步就是手动修改数据目录了:(添加个新节后,导入数据)

OK,收工~


 

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功