6.2.3 C语言直接提取
“直接用C语言来写?”
“嗯,说全部用C语言来写,也不太准确。”老师说,“应该说是ShellCode部分由汇编和C语言混合编程。汇编部分主要是完成动态定位函数地址,而C语言部分是完成程序的功能流程。整个程序的本质,就是让编译器为我们生成二进制代码,然后在运行时编码、打印,这样就完成了一个模板。”
“大家联想一下内存提取和可执行文件提取,就会发现这三种提取方法都是类似的——都是直接把二进制代码拷贝出来。”
“哦!”
“给大家解释一下混合编程的结构以及流程思路吧!C语言直接写ShellCode的思路,最早也可从yuange文章中见到,而hume将其发扬光大。”
“混合编程里有4个函数:ShellCodes函数、DecryptSc函数、PrintSc函数和main函数。”
“在ShellCodes函数里面,生成完成功能的ShellCode,采用的是汇编和C语言混合编程。”老师说道,“首先是汇编部分,就是动态获得每个要使用函数的地址;然后用C语言来直接调用函数,完成想要的功能。”
“DecryptSc函数,是生成解码代码decode的部分;”
“PrintSc函数,是直接把合好的ShellCode按16进制数的形式打印出来。”
“而main函数,就是把各个部分组织起来,以自动化的生成ShellCode并打印出来。”
“具体来说,main函数里面先定义要查找的函数名和所在的模块;然后保存DecryptSc函数生成的decode部分;再把ShellCodes函数生成的代码进行编码,粘贴在decode后面;最后调用PrintSc函数,把最终完成的ShellCode打印出来。其流程如图6-17。”
“其他几个函数都好理解,关键就是ShellCodes函数代码部分的生成。”
“ShellCodes函数分为两大部分,动态获得函数地址就不说了,我们刚才学了几种方法,都是可以的;而高级语言调用函数的部分,hume采用的是枚举方法执行。”
“函数名称数组和枚举数组对应,增加API时只需在相应的.dll后增加函数名称项,并同步更新Enum的索引。调用API时直接使用 API_APINAME; 即可。像这样:”
API[_MessageBeep](0x10);
API[_MessageBoxA](0,testAddr,0,0x40);
API[_ExitProcess](0);
“由此可见,用C语言编写ShellCode需要对代码生成及C编译器行为有更多的了解。有些地方处理起来也不是很省力,不过一旦模板写成,以后写起来或写复杂的ShellCode时,就省力多了。”
“我们来测试一下吧!”大家跃跃欲试。
“程序大家可参看GetShellCodeByC.cpp(光盘有收录)。注意了,我们需要对工程正确的配置才能达到效果。”老师提醒道,“我们要选择release版编译,并去掉优化选项。”
“优化?如何去掉?”
“打开菜单下的‘工程→设置’对话框,在‘C/C++’选项卡下删除‘/02’项,如图6-18。”
“点OK,设置完毕。我们运行,就可弹出测试对话框,并且得到打印好的ShellCode。如图6-19。”
“哇!好方便啊!”
“是啊!大家下来自己测试一下,对应着改变API函数的名称和枚举值,测试完成一下其他的功能。”老师说道。
“好哩!真是太有趣了!”
“大家可要注意整理文档,记下方法。”老师说道,“好记性不如烂笔头,多学多记总有好处的。”