笔记
shellcode:一个可执行代码的有效载荷,包含可执行代码
加载shellcode分析:在IDApro中分析时,选择处理器类型Interl 80x86 processers,并选择32-bit disassembly
使用位置无关代码:
第一条和第二条指令都是通过将EIP寄存器指定的当前位置加上一个保存在指令中的相对偏移值来计算。所以是位置无关代码
第三条指令是一个访问全局数据变量的,并不是一个位置无关代码
第四条指令是使用EBP寄存器作为一个基值,并保含一个符号的相对偏移值,是一个位置无关代码
识别执行位置:以位置无关的方法访问数据时,需要获取一个基地址指针。但x86不提供对EIP的数据访问寻址,也很难得到当前指针值-----mov exa,eip无法执行
1.使用call/pop指令:call指令后面跟一个pop指令滥用,这会将call后面的地址载入指定寄存器中。
pop指令将栈顶指针的地址保存在EDI。所以在pop指令执行后,EDI将包含一个指向红色框处的位置
-L user32--->确认加载user32库
-bp------------>在shellcode执行之前插入断点,允许跳过shellcode_launcher.exe程序的内容,并从shellcode二进制开始执行
设置od为即时调试器-------->Options--Just-in-time Debugging--Make od Just-in-time Debugger选项
2.使用fnstenv指令:当一个进程使用FPU执行浮点运算时,寄存器保存。
图示的位置保留FPU使用的最后一条CPU指令地址
fldz指令将浮点数0.0压到FPU栈上。fpu_instruction_pointer的值变成指向fldz指定的指针。FpuSaveState结构体保存到栈[esp-0ch]处,接来来pop指令将fpu_instruction_pointer值载入到EBX中,这个值指向得位置是fldz指令的位置
手动符号解析:shellcode必须动态定位这些函数,已确保它们在不同环境中都能可靠的工作,所以经常用到LoadLibrary和GetProAddress函数,这两个函数在kernel32.dll中。
内存中寻找kernel32.dll:
FS段寄存器---------->TEB结构-----+0x30----->PEB指针-----+0xc----->PEB_LDR_DATA结构体(包含三个链接LDR_DATA_TABLE结构的双向链表)---------->DllBase
在1处使用fs寄存器访问TEB,获取指向PEB的指针。在4处得到PEB_LDR_DATA结构体,再获取InInitializationOrderLinks链表中的第二个LDR_DATA_TABLE_ENTRY,并返回它的DllBase。
解析PE文件导出数据:
AddressOfFunctions是一个RVA的数组,指向实际导出函数
AddressOfNames是函数名,是一个数组,指向符号名的数组。
AddressOfNameOrdinals是函数序号---16位序号的数组
过程:AddressOfNames数组迭代查找一项和给定的一个字符串比较,找到匹配的项后这个索引称为idx
在AddressOfNameOrdinals数组中使用idx索引,获取到iOrdinal值
使用iOrdinal值索引AddressOfFunctions数组,获取符号的RVA
使用散列过的导出符号名:
开始通过call/pop调用获得执向db 'user32',0的位置。
通过findKernel32Base找到kernel32.dll的基地址
通过findSymbolByHash函数找到散列号为0xEC0E4E8E的函数LoadLibrary
然后通过LoadLibrary加载messageBoxA函数和exit函数
shellcode编码:一些00坏字节要处理掉,隐藏URL和IP地址,躲避网络入侵检测
空指令雪橇:
只要执行到空指令雪橇,就可以滑到解码器的代码
找到shellcode:在JavaScript中,unescape函数用来将编码过的shellcode转化为可执行的二进制文件(大端显示)
在恶意执行文件中,查找典型的进程注入API调用找shellcode有效载荷
在媒体文件中,未编码的形式存在
搜索解码器的操作码字节
实验
Lab19-1
先jmp到short loc_21F,然后call sub_208。在执行call sub_208语句时,会将00000224这里的地址压入栈。
再看sub_208处,先pop esi,这个esi就是00000224这里的地址
图像视图可以看出这里是一个循环,ecx是计数器
LODSB是块读出指令,其具体操作是把SI指向的存储单元读入累加器,其中LODSB是读入AL,然后SI自动增加或减小1或2位。当方向标志位D=0时,则SI自动增加;D=1时,SI自动减小。
SOSB是写入指令,将eax中的内容写入到esi指向的地址中
第一个loadsb读的是数据db 49h到AL寄存器,然后减41h,然后shr左移。第二个loadsb读的是数据db 4Ah到AL寄存器,然后减41h,然后加dl。第三个操作符stosb,将eax的值写入到esi指向的地址处(db 49处)。依次循环。所以这是一个解密操作。
scdbg的显示结果,对shellcode进行分析,这样就可以知道shellcode的大概流程
http://www.freebuf.com/sectool/16320.html
Lab19-2
先创建一个浏览器进程,然后对这个进程就行注入,注入得代码在lpBuffer中unk_407030
unk_407030
这里也是一个解密操作,上面是一个idc解密脚本,其中0x18F是次数
得到shellcode代码后
hash数组
hash数组处理,将函数的hash数值转化为函数的地址
将shellcode提取出来,拿scdbg分析
Lab19-3
用PDFStreamDumper工具,有一个缓冲区溢出的漏洞CVE-2008-2992
http://www.freebuf.com/sectool/1211.html
打开PDF文档时将要被运行的JavaScript脚本,
unescape函数和一个长的文本字符串来初始化攻击负载。Unescape函数的翻译方法是。
%后面跟u:那么就取出后面的4个字符,将它们转化为一个ASCII的十六进制,并且将它转化为2个字节。考虑到大端和小端的情况,输出的顺序会被交换。比如对于“%ue589%uec81”来说,转化后变为“0x89 0xe5 0x81 0xec”。
%后面没有u:则它取出后面2个字符,将他们作为一个ASCII的十六进制,并且将其翻译为1个字节。
拿IDA打开Lab19-03_sc.bin文件,这个是从pdf中提取出来的shellcode。看到只有三行代码可以被识别,然后调用了sub_17B,但在调用sub_17B,把000000D这行的地址压入到了栈中。而这些数据应该就是导入函数的hash值。
注意这段代码地址为0x183位置的call指令所调用的,其实是findKernel32Base函数,用于查找系统中的kernel32.dll的地址。而0x195位置的是findSymbolByHash函数,用于hash值的计算。然后程序在0x19D以及0x1A2的位置压入了“shell32”这个字符串,用于LoadLibrary函数的参数。