反VM虚拟机技术

(1)如果安装了VMware Tools,则使用CreateToolhelp32Snapshot、Process32Next扫描进程列表,查看是否有VMwareService.exe、VMwareTray.exe和VMwareUser.exe
(2)查看网卡地址是否以00:0C:29开头,或查看其它硬件版本
(3)探测内存痕迹,搜索含有VMware的字符串
(4)Red Pill反虚拟机技术->漏洞指令sidt,根据返回的idtr值不同,在多核处理器上无效
(5)No Pill技术->漏洞指令sldt,主机系统上的LDTR值为0,虚拟机中不为0
(6)查看查询I/O通信端口,监视in指令,第二个操作数为VX
(7)查看str指令,主机和虚拟机中返回值不一样,str指令用来从任务寄存器中检索段选择子

措施:
(1)修补代码,使用nop或修改条件跳转
(2)卸载VMware Tools
(3)修改VMware设置
(4)使用多核处理器

PE文件结构

PNTHeader = ImageBase + DosHeader->e_lfanew

DOS首部
IMAGE_DOS_HEADER
PE文件头
IMAGE_NT_HEADERS
IMAGE_FILE_HEADER
IMAGE_OPTIONAL_HEADER32
块表(Section Table)
        IMAGE_SECTION_HEADER
        ……
块(Section)
        .text
.data
        ……
调试信息
        ……

怎样判断一个文件是exe还是dll?

IMAGE_FILE_HEADER 中的文件属性字段中 普通的EXE文件这个字段值一般是010fh,DLL文件这个字段的值是0210h

注意:当磁盘文件一旦被装入内存中,磁盘上的数据结构布局和内存中的数据结构布局是一致的。

虚拟地址(VA) = 基地址(ImageBase) + 相对虚拟地址(RVA)

对抗反汇编

  • 对抗反汇编技术是利用反汇编器的错误假设和局限性来实现的,为了清晰地显示反汇编代码,反汇编器在事前都会做某种特定的假设,一旦这种假设不成立,恶意代码作者就有机会欺骗分析人员

  • 线性反汇编和面向代码流的反汇编

  • 线性反汇编用已经反汇编的指令大小来决定下一个要反汇编的字节,不考虑代码流的控制指令,不能区分代码和数据。

  • 遇到e8指令,将后面四个字节解析成数据(本地call指令5个字节),修改:将后面字节变成指令

  • 如何分辨反汇编:跳转到一个无效指令,相同目标的跳转指令,固定条件的跳转指令,无效的反汇编指令,滥用返回指针retn ->对抗反汇编技术:在条件跳转指令之后放一个流氓字节,从这个字节开始反汇编,阻止其后真正的指令被反汇编,因为插入的字节是一个多字节指令的机器码

反调试

  • 使用windows API探测是否在被调试:IsDebuggerPresent->查询进程环境块(PEB)中的IsDebugged标志
    CheckRemoteDebuggerPresent和上面类似,也是检查查询进程环境块(PEB)中的IsDebugged标志
    NtQueryInformationProcess:第二个参数表示需要提取进程信息的类型,设为ProcessDebugPort
    OutputDebugString:用SetLastError设置错误码,如果在调试,错误码不变
  • 手动检测数据结构:PEB结构中的BeingDebugged、ProcessHeap(进程分配的第一个堆的位置)Flags属性字段
    windbg使用禁用调试堆栈来启动进程
    调试和正常模式下启动进程,它们创建的堆的方式不同,PEB结构偏移量0x68处和0x70比较
  • 系统痕迹检测:检测注册表Aedebug键值是否被修改,查看内存痕迹,查看当前进程列表,通过FindWindow来查找调试器
  • int扫描->使用硬件断点对抗
    执行代码校验和检查:遍历内部指令,然后和一个预设的值进行比较
    时钟检测:被调试时,进程的运行速度大大降低,调试器处理异常的速度非常慢,rdtsc,GetTickCount,QueryPerformanceCounter
  • TLS回调,在进入PE头指定的入口之前运行恶意程序
    IDA中按Ctrl+E组合键看到二进制的入口点,该组合键的作用是显示应用程序所有的入口点
  • 使用异常
  • 插入中断
  • 利用调试器漏洞,OllydDbg1.1格式化漏洞

机器码

jmp:E9  
call:E8  
pop:58  
retn:C3  
int 3 :CC  
rdtsc:0F31 返回系统重新启动以来的时钟数  

断点原理

  • 当关闭程序时,Ollydbg会自动将当前应用程序的断点位置保存在其安装目录*.udd文件中。
  • int 3断点:将断点处的指令替换成CC,会导致一个异常,调试器捕捉这个异常从而停在断点处,然后将断点处的指令恢复到原来指令。
  • 硬件断点:使用四个调试寄存器(DR0,DR1,DR2,DR3)来设定地址,用DR7设定状态,执行到光标所在处(F4)也是利用调试寄存器原理,相当于一次性硬件断点
  • 内存断点:对所设的地址设为不可访问/不可写属性,这样当访问/写入的时候就会产生异常,Ollydbg截获异常后比较异常地址是不是断点地址,如果是就中断。会降低速度,只能实现一个内存断点。
  • 消息断点
  • 条件断点
  • 条件记录断点

函数调用

  • cdecl:从右到左,调用者清理栈,printf
  • stdcall:从右到左,被调用者清理栈
  • fastcall:从右到左,使用edx和ecx寄存器

工具

PEID、Ollydbg、IDA、winhex、PEview、PE Explorer
process explorer查看进程、Resource Hacker查看资源节
promon、dependency walker查看动态链接函数
Immunity Debugger的python编码脚本
snort编写网络特征码
windbg
volatilit:抽取注入的dll程序,搜索隐藏进程
softice

快捷键

ida:交叉引用:ctrl+x  
ollydbg:步入:F7  
歩过:F8:  
回到领空代码:ctrl+F9或Alt+F9  
下断点:F2  
运行到光标处:F4  
运行:F9
查看内存:Alt+M
查看断点:Alt+B

你是如何进行病毒分析的

病毒行为鉴定如果鉴定样本是否为病毒,是通过行为来判断的,大多数病毒的行为有一下几种:
(1) 拷贝自身文件到系统目录下,如system目录,system32目录,windows目录等;
(2) 释放*.DLL文件到系统目录下;
(3) 释放物的取名于系统文件名类似,如svch0st.exe,winlogin.exe等;
(4) 注入进系统进程,如svchost.exe,explorer.exe,iexplore.exe等;
(5) 创建服务,服务的执行路径为病毒文件,大多用来作为自启动;
(6) 病毒文件被设置为隐藏属性;
(7) 设置键盘钩子或鼠标钩子,监视正常用户的操作;
(8) 替换系统文件;
(9) 感染可执行文件;
(10)设置注册表键值,自启动或隐藏;
(11)连接远程地址,下载恶意文件并执行;
(12)开启本地端口,接受来自远程的控制;
(13)修改病毒本身后缀名,如cc3,jpg,tmp等;
(14)创建很隐蔽的路径释放病毒文件。
(15)修改HOST文件;
(16)释放驱动.sys文件篡改系统IDT表等;

是否进行过病毒分析,简述一下过程

(1)搭建虚拟机
(2)用strings查看有没有可疑的字符串
(3)用PEview查看代码入口地址是否有被感染痕迹
(4)用Peid查看是否有壳
(5)开启进程监控软件,监控文件,注册表,进程,搭建网络环境,用wireshark抓包
(6)运行程序,查看程序的行为,判断是否为恶意程序
(7)用调试器动态调试,用IDA静态分析,编写辅助脚本进行分析
(8)对产生的日志和流量进行分析,取证,调研
(9)提取特征码,和已有的样本库进行比对
(10)文档化
(11)备份相关文件

提权

SeDebugPrivilege、OpenProcessToken、LookupPrivilegeValuesA

键盘记录器

用GetAsyncKeyState记录哪个键被按下,用GetForegroundWindow查看聚焦窗口,轮询

是否脱过壳,脱过哪些壳,加壳,脱壳的原理是什么?了解过VMP壳吗?

加壳会打包数据节、代码节、资源节,用压缩算法,虚拟化
脱壳存根:
(1)将原始程序脱壳到内存中
(2)解析原始可执行文件的所有导入函数
(3)将可执行程序转移到原始的程序入口点(OEP)

修复导入表:导入重构器(ImpRec),输入基地址和OEP的偏移值即可

是否了解Hook技术,简述一下原理

  • IAT Hook :修改导入地址表
  • Inline Hook:通过覆盖导入DLL中API函数的代码,必须等到DLL被加载后才能执行
  • SSDT hook:ntoskrnl.exe模块的地址在一定范围内,一旦不在,说明SSDT被hook了

是否对C++的程序有所了解

  • 虚函数中决定调用哪个函数是在运行时进行的
  • C++多态性最大的优势是它允许执行不同功能的对象共享一个公共接口
  • C++使用名字修饰技术来支持方法重载,名字信息中包含了参数信息
  • 每一个使用虚函数的类有它自己的vtable,并且类中的每一个虚函数在vtable 中都有一个项
  • 虚函数表vtable按照偏移值来访问,用sub_####标记,switch偏移表用loc_####标记,子类的虚函数表比父类的大

是否对64位的程序有所了解

  • x64和x86的区别: 所有地址和指针都是64位,通用寄存器数量增加,地址位数也增加,x86不能相对于某个寄存器的偏移寻址,要绝对地址
  • window首先支持的是Itanium,与x86架构不兼容,AMD引入了AMD64的64位架构,与x86兼容。Intel采用了AMD64,并称它的实现为EM64T,这个架构现在被称为x64或x86-64
  • x86的指令不是位置无关的,x64指令将数据地址作为一个相对当前指令指针的偏移进行存储
  • x64调用约定和fastcall最为接近,调用的前4个参数使用RCX、RDX、R8、R9寄存器传递,额外的那些被保存在栈上。
  • x64从不在函数中间改变栈大小
  • x64可以根据某些特性提供额外的线索,如ecx肯定不是存指针,因为指针是64位的。

你对注入有了解吗?

  • 进程注入:VirtualAllocEx函数用来在另外一个进程中分配一块内存空间,WriteProcessMemory函数用来向VirtualAllocEX函数分配的地址空间写数据,分配空间,插入代码
  • DLL注入:强迫一个远程进程加载恶意dll程序,首先查找目标进程,用openProcess获取目标进程的句柄,用CreateRemoteThread在远程进程中创建新线程
  • 直接注入:一般会有两次分配空间,插入代码,一次是写入数据,一次是写入代码
  • 进程替换:dll注入可能让进程崩溃,进程替换的关键是以挂起状态创建,会被载入内存,恢复主线程后,开始执行。调用SetThreadContext,让入口指向恶意代码,调用ResumeThread,初始化并执行恶意程序。