今天,闲来没事。总结了一下自己关于扣别人的加密算法的几个方法。
纯属菜鸟闲谈,高手飘过。
需求: XXX.exe里面有加密算法Encrypt,解密算法Decrypt,偶尔还有算法初始化CryptInit。
【解决办法一】: 直接从IDA中扣出来使用。
步骤1,用ida分析XXX.exe(前提是XXX已经脱壳)。
步骤2,如果加密算法比较短,那么直接复制出来,粘贴到Delphi,VC中使用。
下面是IDA汇编--->delphi汇编的注意修改的地方:
用UE直接批量修改就行。
1, ; -替换成- > //
2, proc near -替换成-> ;assembler;stdcall; //
3, short 删除
4, 添加关键字 Const,asm,在Call头。
5, loc_ -替换成-> @loc_
6, retn -替换成-> ret
7, 特别注意:
ida中这样的语句 cmp al,[ebp-08],这个复制到delphi中是不对的。 要改成 : cmp al,byte ptr [ebp-08]
mov 指令对单字节的处理不需要改。cmp 一定要修改。
8, 当一个Call中有很多 数组需要定义,一定要按照 原来的顺序。
下面是IDA汇编--->VC汇编的注意修改的地方:
IDA汇编复制到VC中,需要修改的地方很少。
1,在IDA中,去掉Call的成员局部变量宏定义。这样可以在VC中不申明宏定义,方便省事。
如果不想去掉局部变量,那么这样写:
int get_code_len(void *code)
{
#define var_14 -0x14
#define var_10 -0x10
................此处省略很多行
__asm _emit 15
__asm _emit 49
2, 在vc的汇编中下面都不需要修改:
1, ; -- > //
2, proc near --> ;assembler;stdcall; //
3, short 删除
4, 添加 Const,asm
5, loc_ --> @loc_
6, retn --> ret
3, VC中纯汇编的call的定义申明。
void __declspec(naked) _stdcall foo();
__declspec(naked) __cdecl AutoGo()
步骤3,如果加密算法Call里面很多子Call,子Call里面又很多子Call,一层一层,太多了,怎么办?
我已经写好了,ida的扣汇编的idc脚本“{请点击下载 扣IDA代码的脚本.rar}”,很简单的只需要指定几个参数,就自动帮你把所需要关联的call全部扣出来。
然后就是继续按照步骤2,搞定。
最后:关于解决办法一,我准备了2个比较典型的范例,可以参考:
附录A: 汇编内嵌VC的范例 -- 轩辕剑Online的通讯加密解密算法。{请点击下载 HGEncrypt.rar}。
附录B: 汇编内嵌Delphi的范例-- 韩国奇迹世界的通讯加密解密算法,这个算法比较复杂带算法初始化的。{请点击下载 UnitGameCrypt.rar}
该方法缺点:每次XXX.exe更新了,工作量都不小,需要重新扣一次,汇编少了还好,
如果汇编很多,有点累。
【解决办法二】:把XXX.exe改写成dll来直接加载使用。
把XXX.exe改成dll,可以参考PEloader的实现原理。
如果懒的看PEloader,那么我告诉你几个注意事项,改一下就行了,也不是很复杂。
关键点:exe的镜像地址是有PE头的 OptionalHeader.ImageBase决定的,
而dll的ImageBaseAddr由LoadLibraryA决定的。
好像只需要修正这一点,就可以了。
{反正我改OD.exe就只改了这个,我很菜,希望高手补充。}
具体怎么改,参考附录C。
最后,把XXX.exe改成了dll,想怎么玩都可以了。
附录C:我把OD.exe ---> OD.dll的修改过程。
1,修改OEP:
OD的OEP:
00DA1000 > $ /EB 10 jmp short 00DA1012
00DA1002 |66 db 66 ; CHAR 'f' //新加的代码不能放这里,因为要重定位。
00DA1003 |62 db 62 ; CHAR 'b'
00DA1004 |3A db 3A ; CHAR ':'
00DA1005 |43 db 43 ; CHAR 'C'
00DA1006 |2B db 2B ; CHAR '+'
00DA1007 |2B db 2B ; CHAR '+'
00DA1008 |48 db 48 ; CHAR 'H'
00DA1009 |4F db 4F ; CHAR 'O'
00DA100A |4F db 4F ; CHAR 'O'
00DA100B |4B db 4B ; CHAR 'K'
00DA100C |90 nop
00DA100D |E9 db E9
00DA100E . |2801E500 dd offset b.___CPPdebugHook
00DA1012 > \A1 1B01E500 mov eax, dword ptr [E5011B]
修改为:
00871000 > /E9 5BE60A00 jmp 0091F660 // + 记录模块地址
00871005 |90 nop
00871006 |90 nop
00871007 |90 nop
00871008 |90 nop
00871009 |90 nop
0087100A |90 nop
0087100B |90 nop
0087100C |90 nop
0087100D |90 nop
0087100E |90 nop
0087100F |90 nop
00871010 |90 nop
00871011 |90 nop
00871012 . |A1 1B019200 mov eax, dword ptr [92011B]
2,加一些代码记录模块地址。
// + 记录模块地址
0091F660 8BC3 mov eax, ebx
0091F662 2D 00100000 sub eax, 1000
0091F667 51 push ecx
0091F668 8BCB mov ecx, ebx
0091F66A 83C1 06 add ecx, 6
0091F66D 8901 mov dword ptr [ecx], eax
0091F66F 59 pop ecx
0091F670 ^ E9 9D19F5FF jmp 00871012 //再跳回去
0091F675 00 db 00
3,在0091F642这里加一个Call,修正GetModuleHandleA的返回,因为现在OD是Dll了,模块地址不同。
0091F628 . 33 32 2D 62 6>ascii "32-bit analysing"
0091F638 . 20 64 65 62 7>ascii " debugger",0
// + 修改 kernel32.GetModuleHandleA
0091F642 $ 8BC4 mov eax, esp
0091F644 . 8378 04 00 cmp dword ptr [eax+4], 0
0091F648 . 74 05 je short 0091F64F
0091F64A .- E9 F2C0EE7B jmp kernel32.GetModuleHandleA
0091F64F > E8 00000000 call 0091F654
0091F654 /$ 58 pop eax
0091F655 |. 2D 4EE60A00 sub eax, 0AE64E
0091F65A |. 8B00 mov eax, dword ptr [eax] //返回上面记录的模块地址
0091F65C \. C2 0400 retn 4
0091F65F 00 db 00
4,最后把调用kernel32.GetModuleHandleA的Call,如果参数为0修改成Call 0091F642,参数不为0的不改。
5,改完,保存为OD.dll,自己随便写一个exe,LoadLibraryA,OD.dll,可以用了
该方法的缺点:如果碰到加密算法,带很强大的算法初始化,或者需要预先下载个什么数据进行初始化,
就需要好好的研究一下XXX的winmian里面都初始化了啥,算法需要怎么的初始化,
不小心遗落的地方,就直接自动关闭了,解决这样的bug,费时不少。
【解决办法三】在XXX.exe中用钩子注入一个b.dll,同时启动c.exe和b.dll通讯 。
b.dll作用:send,recv,把明文加密出来,反馈给c.exe, 或,反之。
步骤1,把b.dll注入到XXX中,在XXX的Encrypt,Decrypt等Call,做几个JMP。
步骤2,通讯可以采用进程通讯,或者窗口发消息。
我比较喜欢窗口发消息,因为可以方便的随时调试查看数据。
参考代码:
//发送调试起信息到 DebugServer
procedure SendDebugMes(Str: string);
var
N: THandle;
CS: TCopyDataStruct ;
begin
N := Findwindow(nil, 'DebugServer');
if N = 0 then exit;
cs.dwData := 0;
Cs.lpData := Pchar(Str);
cs.cbData := Length(Str);
SendMessage(N, WM_COPYDATA, 0, DWORD(@cs));
end;
总结:方法三该初始化的地方肯定初始化了,
就算XXX经常更新,也无所谓,只需要 记录个特征码,自动搜索定位就是了。{自动搜索定位Call地址,参见,附录D}
//搜索内存,定位Call地址
procedure SearchInMemory(pSearchInfo: PTSearchInfo);
var
i: DWord;
pcKey: PChar;
nlen: DWord;
nDisplace: DWord;
pValResult: Pointer;
pValAddress: Pointer;
dwStartAddr: DWord;
dwEndAddr: DWord;
label NoFound;
begin
try
if pSearchInfo = nil then exit;
if pSearchInfo^.bAutoScan = False then exit;
pSearchInfo^.nResult := 0;
nDisplace := pSearchInfo^.nDisplace;
pValResult := @(pSearchInfo^.nResult);
pValAddress := @(pSearchInfo^.dwAddress);
nLen := pSearchInfo^.nKeyLen;
pcKey := pSearchInfo^.pcSearchKey;
dwStartAddr := pSearchInfo^.dwStartAddr;
dwEndAddr := pSearchInfo^.dwEndAddr;
if nLen > 16 then exit;
for i := dwStartAddr to dwEndAddr do
begin
asm
pushad
mov ecx,nLen
mov edi,i
mov esi,pcKey
repz cmpsb
jne NoFound
cmp ecx,0
jnz NoFound
mov eax,nDisplace
add eax,i
mov edx,[pValAddress]
mov [edx],eax
mov ecx,[eax]
mov edx,[pValResult]
mov [edx],ecx
popad
end;
break;
NoFound:
asm
popad
end;
end;
end;
最后,提供常用的加密算法源码集,有好几百个。其中包括QQ的加密算法tea。
附录D:{请点击下载 code300_C.rar}
附录A:{请点击下载 HGEncrypt.rar}。
附录B: {请点击下载 UnitGameCrypt.rar}
附录C:ida的扣汇编的idc脚本“{请点击下载 扣IDA代码的脚本.rar}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!