分析的不是很好,有些东西没表达清楚,大家自己分析一哈,这个程序是我自己写的个进程管理,还没写完。。。。
UPX3.03加壳,加壳时选了加密处理,高级导入保护,模拟系统标准功能,但是再外壳段好像并没见到这几个功能。
先来个CALL公式,等会要用到。具体见附件,自己分析哈
代码:
CALL 地址计算公式:CALL下条指令开始 + E8后面的绝对偏移 = 目标地址 例如 00401B2C是当前地址,5是CALL机器码的长度;E8 CF 00 00 00是机器码 计算: 00401B2C+5+CF=00401C00 E8 CF 00 00 00就是表示CALL 00401C00. 例二: 00401B3B |. E8 C0270000 CALL decode.00404300 00401B3B+5+27C0=00404300,地址就是:CALL 00404300 例三: 00401B5F |. E8 3C1B0000 CALL decode.004036A0 00401B5F+5+1B3C=004036A0,地址就是:CALL 004036A0 00401B5F+5=下条指令开始的地址,向后移动1B3C就是目标指令的开始地址 00417550 > $ 60 PUSHAD 00417551 . BE 15604100 MOV ESI,进程管理.00416015 00417556 . 8DBE EBAFFEFF LEA EDI,DWORD PTR DS:[ESI+FFFEAFEB] ; 得到代码段的开始地址放在EDI里面 0041755C . 57 PUSH EDI 0041755D . EB 0B JMP SHORT 进程管理.0041756A 0041755F 90 NOP 00417560 > 8A06 MOV AL,BYTE PTR DS:[ESI] ; 现在分析得知00416015这个地址是我们程序代码段的开始地址,被映射到这里了,取出映射的代码的一字节 00417562 . 46 INC ESI ; 指向我们代码的下个字节 00417563 . 8807 MOV BYTE PTR DS:[EDI],AL ; EDI现在是从00401000开始的,把映射的代码放入原来我们代码的地址,那么现在知道在开始代码还原了 00417565 . 47 INC EDI ; 指向我们代码的下个地址,以便存放下个字节 00417566 > 01DB ADD EBX,EBX ; EBX+EBX,当EBX不等于0的时候就跳,那么下面如果进位加法为0,那么取出下个地址到EBX 00417568 . 75 07 JNZ SHORT 进程管理.00417571 0041756A > 8B1E MOV EBX,DWORD PTR DS:[ESI] ; 00416015这个地址放到EBX里面, 0041756C . 83EE FC SUB ESI,-4 ; 00416015加4 0041756F . 11DB ADC EBX,EBX ; 进位加法器 00417571 >^ 72 ED JB SHORT 进程管理.00417560 ; 向上跳,EBX作为跳不跳的标志,循环处理代码,一个大循环 00417573 . B8 01000000 MOV EAX,1 ; EAX=1 00417578 > 01DB ADD EBX,EBX ; EBX再加EBX,EBX在这个代码里面作为跳转标志 0041757A . 75 07 JNZ SHORT 进程管理.00417583 0041757C . 8B1E MOV EBX,DWORD PTR DS:[ESI] ; ESI指向的地址到EBX 0041757E . 83EE FC SUB ESI,-4 ; ESI加上4 00417581 . 11DB ADC EBX,EBX ; 进位加法 00417583 > 11C0 ADC EAX,EAX ; 进位加法 00417585 . 01DB ADD EBX,EBX ; EBX+EBX 00417587 .^ 73 EF JNB SHORT 进程管理.00417578 00417589 . 75 09 JNZ SHORT 进程管理.00417594 ; 跳转到下面 0041758B . 8B1E MOV EBX,DWORD PTR DS:[ESI] 0041758D . 83EE FC SUB ESI,-4 00417590 . 11DB ADC EBX,EBX 00417592 .^ 73 E4 JNB SHORT 进程管理.00417578 00417594 > 31C9 XOR ECX,ECX ; ECX清零 00417596 . 83E8 03 SUB EAX,3 ; EAX减去3 00417599 . 72 0D JB SHORT 进程管理.004175A8 0041759B . C1E0 08 SHL EAX,8 ; EAX逻辑左移8位 0041759E . 8A06 MOV AL,BYTE PTR DS:[ESI] ; ESI指向的地址取出一字节到AL 004175A0 . 46 INC ESI ; 指向我们代码的下个字节 004175A1 . 83F0 FF XOR EAX,FFFFFFFF ; EAX和FFFFFFFF异或 004175A4 . 74 74 JE SHORT 进程管理.0041761A 004175A6 . 89C5 MOV EBP,EAX ; EAX放到EBP里面 004175A8 > 01DB ADD EBX,EBX ; EBX加上EBX 004175AA . 75 07 JNZ SHORT 进程管理.004175B3 ; 判断跳转,这次是跳 004175AC . 8B1E MOV EBX,DWORD PTR DS:[ESI] 004175AE . 83EE FC SUB ESI,-4 004175B1 . 11DB ADC EBX,EBX 004175B3 > 11C9 ADC ECX,ECX ; 进位加法 004175B5 . 01DB ADD EBX,EBX ; EBX乘以2 004175B7 . 75 07 JNZ SHORT 进程管理.004175C0 004175B9 . 8B1E MOV EBX,DWORD PTR DS:[ESI] 004175BB . 83EE FC SUB ESI,-4 004175BE . 11DB ADC EBX,EBX 004175C0 > 11C9 ADC ECX,ECX ; 进位加法 004175C2 . 75 20 JNZ SHORT 进程管理.004175E4 004175C4 . 41 INC ECX 004175C5 > 01DB ADD EBX,EBX 004175C7 . 75 07 JNZ SHORT 进程管理.004175D0 004175C9 . 8B1E MOV EBX,DWORD PTR DS:[ESI] 004175CB . 83EE FC SUB ESI,-4 004175CE . 11DB ADC EBX,EBX 004175D0 > 11C9 ADC ECX,ECX 004175D2 . 01DB ADD EBX,EBX 004175D4 .^ 73 EF JNB SHORT 进程管理.004175C5 004175D6 . 75 09 JNZ SHORT 进程管理.004175E1 004175D8 . 8B1E MOV EBX,DWORD PTR DS:[ESI] 004175DA . 83EE FC SUB ESI,-4 004175DD . 11DB ADC EBX,EBX 004175DF .^ 73 E4 JNB SHORT 进程管理.004175C5 004175E1 > 83C1 02 ADD ECX,2 004175E4 > 81FD 00F3FFFF CMP EBP,-0D00 ; 迷惑指令 004175EA . 83D1 01 ADC ECX,1 ; 进位加法 004175ED . 8D142F LEA EDX,DWORD PTR DS:[EDI+EBP] ; 装入EDI+EBP的地址到EDX,现在他们指向我们原来的代码段 004175F0 . 83FD FC CMP EBP,-4 ; 判断跳转标志,EBP低于等于-4就跳,也就是EBP至少要是-4才跳 004175F3 . 76 0F JBE SHORT 进程管理.00417604 004175F5 > 8A02 MOV AL,BYTE PTR DS:[EDX] ; EDX指向我们的代码段取出一字节,到AL里面 004175F7 . 42 INC EDX ; 指向下个字节的地址 004175F8 . 8807 MOV BYTE PTR DS:[EDI],AL ; 放入现在我们处理的代码,也就是刚才上面没处理的我们代码段 004175FA . 47 INC EDI ; 指向下个地址,用于接收下个字节码 004175FB . 49 DEC ECX ; 计数器,ECX, 004175FC .^ 75 F7 JNZ SHORT 进程管理.004175F5 ; ECX作为计数器的跳转,当ECX不为0就继续处理 004175FE .^ E9 63FFFFFF JMP 进程管理.00417566 ; 向上跳转,跳到第一个ADD EBX,EBX那里 00417603 90 NOP 00417604 > 8B02 MOV EAX,DWORD PTR DS:[EDX] ; 这里处理程序中的数据和CALL,就是输入表 00417606 . 83C2 04 ADD EDX,4 ; 指向下个地址 00417609 . 8907 MOV DWORD PTR DS:[EDI],EAX ; 取出的代码放到EDI里面,EDI一直指向我们没处理完的代码的地址 0041760B . 83C7 04 ADD EDI,4 ; EDI加上4,代码接收段的地址+4 0041760E . 83E9 04 SUB ECX,4 ; ECX减去4 00417611 .^ 77 F1 JA SHORT 进程管理.00417604 00417613 . 01CF ADD EDI,ECX ; EDI加上ECX,指向前刚才接收代码的地址的前字节,也就是最后的一字节 00417615 .^ E9 4CFFFFFF JMP 进程管理.00417566 ; 又跳到刚才的第一个ADD EBX,EBX 0041761A > 5E POP ESI 0041761B . 89F7 MOV EDI,ESI 0041761D . B9 4B000000 MOV ECX,4B 00417622 > 8A07 MOV AL,BYTE PTR DS:[EDI] ; 指向我们原来代码段的代码,取出到AL里面,下面开始处理CALL,这种CALL就是调用一个地址那种,下面计算它的绝对偏移 00417624 . 47 INC EDI ; 指向下个字节 00417625 . 2C E8 SUB AL,0E8 ; AL减去E8,判断是否为E8,也就是CALL,这里处理CALL 00417627 > 3C 01 CMP AL,1 ; 比较AL是否高于1 00417629 .^ 77 F7 JA SHORT 进程管理.00417622 ; 这里循环,一直到碰到下个CALL的字节,CALL就是E8嘛 0041762B . 803F 00 CMP BYTE PTR DS:[EDI],0 ; 判断EDI是否等于0,也就是处理CALL,下面就计算CALL的绝对地址,就是E8后面那个字节码,不是处理函数那种CALL,大家看下我写的那个CALL公式 0041762E .^ 75 F2 JNZ SHORT 进程管理.00417622 00417630 . 8B07 MOV EAX,DWORD PTR DS:[EDI] ; 取出里面的地址,里面的地址是定位CALL的绝对地址要用到的 00417632 . 8A5F 04 MOV BL,BYTE PTR DS:[EDI+4] ; 得到下条地址的开始字节到AL里面,CALL绝对地址就是下条指令开始+刚才上面取出的那个数字 00417635 . 66:C1E8 08 SHR AX,8 ; AX逻辑右移8位 00417639 . C1C0 10 ROL EAX,10 ; EAX算术左移8位 0041763C . 86C4 XCHG AH,AL ; 交换他们的内容 0041763E . 29F8 SUB EAX,EDI ; EAX减去这个地址EDI 00417640 . 80EB E8 SUB BL,0E8 ; 再减去E8 00417643 . 01F0 ADD EAX,ESI ; EAX加上ESI,ESI这里是代码段开始的地址 00417645 . 8907 MOV DWORD PTR DS:[EDI],EAX ; 这里处理CALL的地址,算出CALL的偏移到EDI里面,当CALL得到偏移之后自动计算地址 00417647 . 83C7 05 ADD EDI,5 ; EDI加上5,表示CALL已经被处理,指向CALL的后面 0041764A . 88D8 MOV AL,BL ; BL的数据放到AL里面 0041764C .^ E2 D9 LOOPD SHORT 进程管理.00417627 ; 向上跳转,处理下个CALL ,ECX作为计数器,就是后面这种CALL 的数量就比如 CALL 00401000,这种CALL 0041764E . 8DBE 00500100 LEA EDI,DWORD PTR DS:[ESI+15000] ; CALL 00401000这种的绝对地址计算处理完毕,现在代码段开始地址+15000的地址到EDI里面 00417654 > 8B07 MOV EAX,DWORD PTR DS:[EDI] ; 现在EDI指向我们的代码的输入表 00417656 . 09C0 OR EAX,EAX ; 判断EAX是否为0 00417658 . 74 45 JE SHORT 进程管理.0041769F 0041765A . 8B5F 04 MOV EBX,DWORD PTR DS:[EDI+4] ; 取得这个地址的数据到EBX里面 0041765D . 8D8430 C47802>LEA EAX,DWORD PTR DS:[EAX+ESI+278C4] ; 取得外壳段的KERNEL32.DLL的地址到EAX里面 00417664 . 01F3 ADD EBX,ESI ; 我们代码段的开始地址加上刚才取出的那个数据 00417666 . 50 PUSH EAX ; KERNEL32.DLL的地址 00417667 . 83C7 08 ADD EDI,8 ; EDI加上8 0041766A . FF96 28790200 CALL DWORD PTR DS:[ESI+27928] ; 装载KERNEL32.DLL 00417670 . 95 XCHG EAX,EBP ; EAX的值和EBX交换,现在EAX是指向KERNEL32.DLL的基址 00417671 > 8A07 MOV AL,BYTE PTR DS:[EDI] ; 取得现在的EDI的地址指向的数据到AL里面,每个函数名字前面有个01,以便判断获得函数的名字 00417673 . 47 INC EDI ; 指向下个字节的地址,下个地址就是我们的函数名字了 00417674 . 08C0 OR AL,AL ; 判断AL是否为0 00417676 .^ 74 DC JE SHORT 进程管理.00417654 00417678 . 89F9 MOV ECX,EDI ; 我们的函数的名字放到ECX里面 0041767A . 79 07 JNS SHORT 进程管理.00417683 ; SF符号为正就跳 0041767C . 0FB707 MOVZX EAX,WORD PTR DS:[EDI] 0041767F . 47 INC EDI 00417680 . 50 PUSH EAX 00417681 . 47 INC EDI 00417682 B9 DB B9 00417683 . 57 PUSH EDI ; 我们的函数名字 00417684 . 48 DEC EAX ; EAX减去1 00417685 . F2:AE REPNE SCAS BYTE PTR ES:[EDI] 00417687 . 55 PUSH EBP ; KERNEL32的基址 00417688 . FF96 2C790200 CALL DWORD PTR DS:[ESI+2792C] ; 外壳段的GetProcAddress 0041768E . 09C0 OR EAX,EAX ; 得到函数的地址 00417690 . 74 07 JE SHORT 进程管理.00417699 00417692 . 8903 MOV DWORD PTR DS:[EBX],EAX ; 放到我们的外壳段中的函数调用的地址,也就是处理输入表 00417694 . 83C3 04 ADD EBX,4 ; 指向下个输入表中的地址 00417697 .^ EB D8 JMP SHORT 进程管理.00417671 00417699 > FF96 3C790200 CALL DWORD PTR DS:[ESI+2793C] 0041769F > 8BAE 30790200 MOV EBP,DWORD PTR DS:[ESI+27930] ; VirtualProtect的地址放到EBP里面 004176A5 . 8DBE 00F0FFFF LEA EDI,DWORD PTR DS:[ESI-1000] ; 指向PE头的地址,也就是映像基址 004176AB . BB 00100000 MOV EBX,1000 ; EBX 等于1000 004176B0 . 50 PUSH EAX 004176B1 . 54 PUSH ESP 004176B2 . 6A 04 PUSH 4 004176B4 . 53 PUSH EBX 004176B5 . 57 PUSH EDI 004176B6 . FFD5 CALL EBP ; 改变属性 004176B8 . 8D87 9F010000 LEA EAX,DWORD PTR DS:[EDI+19F] ; 现在EAX指向PE头中区段的偏移开始 004176BE . 8020 7F AND BYTE PTR DS:[EAX],7F ; 改写区段名字 004176C1 . 8060 28 7F AND BYTE PTR DS:[EAX+28],7F ; 改写区块属性第一个区块的属性 004176C5 . 58 POP EAX 004176C6 . 50 PUSH EAX 004176C7 . 54 PUSH ESP 004176C8 . 50 PUSH EAX 004176C9 . 53 PUSH EBX 004176CA . 57 PUSH EDI 004176CB . FFD5 CALL EBP 004176CD . 58 POP EAX