易语言教程_易语言源码_易语言写挂_易语言论坛_看流星社区

 找回密码
 注册
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
零基础辅助入门教学 原创 高清 专业课程售后(每日解答)
赞助广告位 请点击这里联系站长 QQ20209081
赞助广告位 请点击这里联系站长 QQ20209081
赞助广告位 请点击这里联系站长 QQ20209081
查看: 1383|回复: 1

关于通过反汇编查看dll的方法

[复制链接]
发表于 2013-2-20 09:56:07 | 显示全部楼层 |阅读模式
今天想看一个dll的内容,苦于没有相关工具,从csdn上找到有这么段文字,收益匪浅啊,收藏!

可以通过反汇编来知道接口函数的参数,建议使用W32DSM来分析,也可以直接使用VC来分析,就是麻烦一点。  
  现在使用W32DSM来具体说明:  
  1。先打开需要分析的DLL,然后通过菜单功能-》出口来找到需要分析的函数,双击就可以了。  
  它可以直接定位到该函数。  
  2。看准该函数的入口,一般函数是以以下代码作为入口点的。  
  push   ebp  
  mov     ebp,   esp  
  ...  
  3。然后往下找到该函数的出口,一般函数出口有以下语句。  
  ...  
  ret     xxxx;//其中xxxx就是函数差数的所有的字节数,为4的倍数,xxxx除以4得到的结果  
  就是参数的个数。  
  其中参数存放的地方:  
  ebp+08           //第一个参数  
  ebp+0C           //第二个参数  
  ebp+10           //第三个参数  
  ebp+14           //第四个参数  
  ebp+18           //第五个参数  
  ebp+1C           //第六个参数  
  。。。。  
  -------------------------------------------  
  还有一种经常看到的调用方式:  
  sub   esp,xxxx           //开头部分  
  //函数的内容  
  。。。  
  //函数的内容  
  add   esp,xxxx  
  ret                             //结尾部分  
  其中xxxx/4的结果也是参数的个数。      
  -------------------------------------------------  
  还有一种调用方式:  
  有于该函数比较简单,没有参数的压栈过程,  
  里面的  
  esp+04就是第一个参数  
  esp+08就是第二个参数  
  。。。  
  esp+xx就是第xx/4个参数  
  你说看到的xx的最大数除以4后的结果,就是该函数所传递的参数的个数。  
  ----------------------------------------------  
  到现在位置,你应该能很清楚的看到了传递的参数的个数。至于传递的是些什么内容,还需要进一步的分析。  
  最方便的办法就是先找到是什么软件在调用此函数,然后通过调试的技术,找到该函数被调用的地方。一般都是PUSH指令  
  来实现参数的传递的。这时可以看一下具体是什么东西被压入堆栈了,一般来说,如果参数是整数,一看就可以知道了,  
  如果是字符串的话也是比较简单的,只要到那个地址上面去看一下就可以了。  
  如果传递的结构的话,没有很方便的办法解决,就是读懂该汇编就可以了。对于以上的分析,本人只其到了抛砖引玉,  
  希望对大家有点用处。  
  昨天已经简单的告诉大家,怎么知道接口的参数个数了,以及简单的接口。由于编译器的优化原因,  
  可能有的参数没有我前面说的那么简单,今天就让我再来分析一下的DLL的调用的接口。如果在该DLL的  
  某个函数中,有关于API调用的话,并且调用API的参数整好有一个或多个是该DLL函数的参数的话。  
  那么就可以很容易的知道该DLL函数的参数了。  
  举例说明:以下汇编代码通过W32DSM得到。  
  Exported   fn():   myTestFunction   -   Ord:0001h  
  :10001010   8B442410                                 mov   eax,   dword   ptr   [esp+10]  
  :10001014   56                                             push   esi  
  :10001015   8B74240C                                 mov   esi,   dword   ptr   [esp+0C]  
  :10001019   0FAF742410                             imul   esi,   dword   ptr   [esp+10]  
  :1000101E   85C0                                         test   eax,   eax  
  :10001020   7414                                         je   10001036  
  :10001022   8B442418                                 mov   eax,   dword   ptr   [esp+18]  
  :10001026   8B4C2408                                 mov   ecx,   dword   ptr   [esp+08]  
  :1000102A   6A63                                         push   00000000  
  :1000102C   50                                             push   eax  
  :1000102D   51                                             push   ecx  
  :1000102E   6A00                                         push   00000000  
   
  *   Reference   To:   USER32.MessageBoxA,   Ord:01BEh  
                                                                      |  
  :10001030   FF15B0400010                         Call   dword   ptr   [100040B0]  
   
  *   Referenced   by   a   (U)nconditional   or   (C)onditional   Jump   at   Address:  
  |:10001020(C)  
  |  
  :10001036   8BC6                                         mov   eax,   esi  
  :10001038   5E                                             pop   esi  
  :10001039   C3                                             ret  
  -------------------------------------------------------  
  其中myTestFunction是需要分析的函数,它的里面调用了USER32.MessageBoxA  
  这个函数计算参数个数的时候要注意了,它不是0X18/4的结果,原因是程序入口  
  的第二条语句又PUSH了一下,PUSH之前的ESP+10就是第4个参数,就是0x10/4   =4  
  PUSH之后的语句ESP+   XX,  
  其中(XX-4)/4才对应于第几个参数。  
  ESP+0C   ==第2个参数  
  ESP+10   ==第3个参数  
  ESP+18   ==第5个参数  
  ESP+08   ==第1个参数  
  ----------------------------这样共计算出参数的个数是5个,注意PUSH   esi之前与PUSH   esi之后,  
  PUSH一下,ESP的值就减了4,特别需要注意的地方!!!然后看函数的返回处RET指令,  
  由于看到了RET之前给EAX赋了值,所以可以知道该函数就必定返回了一个值,大家都知道EAX的寄存器  
  是4个字节的,我们就把它用long来代替好了,现在函数的基本接口已经可以出来了,  
  long   myTestFunction(long   p1,long   p2,long   p3,long   p4,long   p5);  
  但是具体的参数类型还需调整,如果该函数里面没有用到任何一个参数的话。那么参数  
  多少于参数的类型就无所谓了。一般来说这是不太会遇到的。那么,我们怎么去得到该函数的  
  参数呢?请看下面分析:  
              你有没有看到*   Reference   To:   USER32.MessageBoxA,   Ord:01BEh这一条语句,  
  这说明了,在它的内部使用了WINAPI::MessageBox函数,我们先看一下它的定义:  
  int   MessageBox(  
      HWND   hWnd,                     //   handle   of   owner   window  
      LPCTSTR   lpText,           //   address   of   text   in   message   box  
      LPCTSTR   lpCaption,     //   address   of   title   of   message   box  
      UINT   uType                     //   style   of   message   box  
  );  
  它有4个参数。一般我们知道调用API函数的参数是从右往左压入堆栈的,把它的调用过程  
  翻译为伪ASM就是:  
                              PUSH   uType  
                              PUSH   lpCaption   
                              PUSH   lpText  
                              PUSH   hWnd  
                              CALL   MessageBox  
  ---------------------------------------  
  我们把这个于上面的语句对应一下,就可以清楚的知道  
  hWnd               =   NULL(0)  
  lpText           =   ecx  
  lpCaption     =   eax  
  uType             =   MB_OK(0)  
  ---------------------------------  
  在往上面看,  
  原来   EAX   中的值是ESP+18中的内容得到了  
            ECX   中的值是ESP+08中的内容得到了  
   
  那么到现在为止就可以知道  
  lpText         =   ECX   =   [ESP+08]         ==第1个参数  
  lpCaption   =   EAX   =   [ESP+18]         ==第5个参数  
   
  现在我们可以把该DLL函数接口进一步写成:  
  long   myTestFunction(LPCTSTR   lpText,long   p2,long   p3,long   p4,LPCTSTR   lpCaption);  
   
  至于第3个参数ESP+10,然后找到该参数使用的地方,imul   esi,   dword   ptr   [esp+10]有这么一条指令。  
  因为imul是乘法指令,我们可以肯定是把ESP+10假设位long是不会错的,同理可以知道第2个参数esp+0C  
  肯定用long也不会错了,至于第4个参数,它只起到了一个测试的作用,  
  mov   eax,   dword   ptr   [esp+10]  
  test   eax,   eax  
  je   10001036  
  看到这个参数的用法了吗?  
  把它翻译位C语言就是:  
  if(p3)  
  {  
          //做je   10001036下面的那些指令  
  }  
  return   ;  
  到现在为止可以把第3个参数看成是个指针了吧!就是如果p3为空就直接返回,如果不空就做其它一下事情。  
   
  好了,到现在位置可以把正确的接口给列出来了:  
  long   myTestFunction(LPCTSTR   lpText,long   n1,char   *pIsNull,long   n2,LPCTSTR   lpCaption);  
  哈哈,现在成功了!!!  
  long   CryptExtOpenCER(long   p1,long   p2,LPCSTR   p3,long   p4);  
  其中第3个参数可能是文件名称,  
  或者是PCERT_BLOB  
  它有CERT_QUERY_OBJECT_FILE,或者是CERT_QUERY_OBJECT_BLOB来决定。  
  ---------------------------------------------------------------  
  今天想到了一个很好的办法,来解决参数的问题,不过有一定难度。  
  1。根据以前讲的各种方法,可以很快速的知道参数的个数,假设该函数  
  名称为MyTestFunc,参数的个数为3个。  
  于是可以定义如下:  
  long   MyTestFunc(long   p1,long   p2,long   p3);  
  2。安装一个HOOK(DLL)  
  3。通过别的程序调用,触发HOOK,调试到HOOK里面,就可以很清楚的知道  
  调用的参数,数值。  
  -------------  
  此方法本人还没有去实现,相信肯定是可以的。这样得到的参数应该相当准确。
发表于 2013-5-3 18:46:21 | 显示全部楼层
谢谢分享。不过我觉得C语言的参数是从右往左传递的吧?既ebp+08 第四个参数 ebp+0c 第三个参数…………

新手不懂,不要见笑
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|看流星社区  |网站地图

GMT+8, 2018-9-19 03:59 易语言论坛 易语言导航

Powered by 看流星社区 X3.2

©2011-2016 最好的辅助编程技术论坛

快速回复 返回顶部 返回列表