首页
社区
课程
招聘
[原创]关于解决加密算法的那些事
发表于: 2013-5-30 00:23 27404

[原创]关于解决加密算法的那些事

2013-5-30 00:23
27404

今天,闲来没事。总结了一下自己关于扣别人的加密算法的几个方法。
纯属菜鸟闲谈,高手飘过。

需求: 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


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 5
支持
分享
最新回复 (46)
雪    币: 4560
活跃值: (1002)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
不错,收藏了
2013-5-30 00:43
0
雪    币: 437
活跃值: (78)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
很有必要收藏。
2013-5-30 02:29
0
雪    币: 81
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
谢谢分享   收藏了
2013-5-30 07:43
0
雪    币: 224
活跃值: (24)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
果断收藏,感谢分享
2013-5-30 09:38
0
雪    币: 602
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
好文,要顶
2013-5-30 11:01
0
雪    币: 114
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
经验之谈 智慧的结晶啊··楼主愿意分享 难能可贵!
2013-5-30 11:11
0
雪    币: 141
活跃值: (318)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
这个不错呀,能用到,嘿嘿
2013-5-30 12:13
0
雪    币: 221
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
下载留名
2013-5-30 12:38
0
雪    币: 27
活跃值: (127)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
10
逆向作为职业2年多了,上面这些法子基本都用过。
在逆向工程中,当被逆向的目标程序不断更新时,怎么快速使逆向出的源码保持同步更新。
楼主讲讲经验。
2013-5-30 12:55
0
雪    币: 34
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
收藏了,谢谢分享
2013-5-30 14:25
0
雪    币: 1024
活跃值: (240)
能力值: ( LV12,RANK:310 )
在线值:
发帖
回帖
粉丝
12
后面的太复杂了 脚本直接调用ida调试器搞定 还可以加注释
2013-5-30 14:33
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
很好,搜藏一下
2013-5-30 16:03
0
雪    币: 11
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
看着感觉压力很大,菜鸟看过
2013-5-30 16:05
0
雪    币: 11050
活跃值: (17555)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
先收藏帖子了,等以后技术提升再来学习
2013-5-30 16:26
0
雪    币: 862
活跃值: (329)
能力值: ( LV9,RANK:165 )
在线值:
发帖
回帖
粉丝
16
感谢分享~~
2013-5-30 17:28
0
雪    币: 1270
活跃值: (109)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
17
学习一下加密算法。谢谢分享。
2013-5-30 17:30
0
雪    币: 43
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
不错。关于那个“解决办法3”,再开一个c.exe是不是麻烦一些。在那个dll里直接嵌一个lua(luajit),再加一个简单的gui库,然后再封装几个常用的操作,hook,memory read/write/copy,甚至是libudis, distorm,当一个小型的内嵌调试器用,感觉会更方便
2013-5-30 17:49
0
雪    币: 65
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
收藏 + 印章
2013-5-30 21:15
0
雪    币: 74
活跃值: (748)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
感谢分享
2013-5-30 21:49
0
雪    币: 107
活跃值: (37)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
改失败我用现成的DLLOD了,楼主也是DELPHIER
2013-5-30 23:50
0
雪    币: 143
活跃值: (263)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
22
good idea ,thanks for share
2013-5-31 10:41
0
雪    币: 264
活跃值: (135)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
收藏了,好强大
2013-5-31 13:08
0
雪    币: 546
活跃值: (1637)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
24
如果是同一个程序,他出新版本一般算法不会有太大变化,可能就是一些密钥的改变,常量的改变,偶尔会改变一下加密流程。但是只要你准确的分析出它一个版本,后面的都不会有太大变化,如果有大变化,那你就得详细分析了,分析玩,它在更新,还是围着最新的这个进行一些小改动。
2013-5-31 16:32
0
雪    币: 190
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
25
恩恩,屌炸了,留名
2013-5-31 19:03
0
游客
登录 | 注册 方可回帖
返回
//