【文章标题】: Themida1.9.1.0版的通法破解
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
        感谢kanxue坛主和okdodo大师提供的插件。
  
        上一篇文章《Themida的另类破解》只适用于Themida v1.8.5.5版本。那时我还以为它是Themida的最高版本,因为我用的Themida是从www.pediy.com的工具页上下载的,标签是new(现在也如此)!直到文章发表后网友问能否用于Themida v1.9.1.0时,我才在网上看到了它,下载后加密了几个软件后,才知道它的利害!经过十多天的努力,终于也给破了。
  
      一、请下载okdodo大师的插件“invisible”
      用Themida1.9.1.0版加密的软件,有很强的反anti能力,在OD v1.10版上不能运行。请在bbc.pediy.com的精华篇中下载okdodo的插件“invisible.dll”,添加到OD文件夹的plugin中,并删除HideOD.dll(或改名为HideOD.dll.bak)。这样Themida v1.9.1.0加密的软件就可以在OD中运行了。
  
      二、Themida v1.9.1.0的通法破解
      因为1.9.1.0版本是1.8.5.5版本的升级,在重要的代码段中随机插入了大量的垃圾代码和花指令。不同的软件,甚至同一软件第二次加密其代码都是不一样的!这跟破解的“通用性”带来极大困难。但我终于搞出了一个通用的破解方法!但要使用三个脚本,反复用OD加载要解密的软件。三个脚本分别叫:脚本1(断点侦测)、脚本2(API修复)、脚本3(OEP修复)。
  
      1.脚本1(断点侦测)的使用:脚本如下(已改进为全自动了,用它替换附件中的脚本1)
      -------------------------------------------
    //Themida 1.9.1.0的断点设置脚本(改进版)
data:
  var memory
  var csize
  var tmp
  var temp
  var tmpbp
  var mem
  var mem0
        var mem1
  var mem2
  var mem3
   var mem4
  var mem5
  var Str0
  var Str3
  var Str4
  var Str5
  var Str1
        var Str2
star:
  gmi eip,CODEBASE
        mov  memory,$RESULT
        gmi eip,CODESIZE
  mov csize,$RESULT
        add csize,memory  
  find memory,#0000000000000000000000000000000000000000000000#
  mov tmp,$RESULT
  bphws tmp,"w"
        esto
  esto
  esto
  bphwc tmp
  sto
  find memory,#0000000000000000000000000000000000000000000000#
  mov tmp,$RESULT
        sub csize,tmp
        find memory,#909090909090909090909090909090909090#
  mov temp,$RESULT+8
  bphws temp,"w"
  mov  tmpbp,eip
  run
  cmp  eip,tmpbp+2
        jnz  next
        run
  next:
  bphwc
        mov  Str0,"断点地址:"
        add  Str0,#0D0A#
  mov  mem,eip
  mov  mem4,eip           //eip=Addr_4
  itoa eip
  mov  Str4,"Addr_4="
        add  Str4,$RESULT
        add  Str4,#0A0D#
        find mem4,#83BD????????000F8497000000#
        mov  mem5,$RESULT       //Addr_5
        itoa mem5 
        mov  Str5,"Addr_5="
        add  Str5,$RESULT 
        sub  mem,4000 
  find mem,#83BD????????640F82??020000#
        mov  mem0,$RESULT+7    //Addr_0
        itoa mem0
        add  Str0,"Addr_0="
        add  Str0,$RESULT 
        add  Str0,#0D0A#
        find mem0,#C1C003#
        find $RESULT,#0385????7409#,40
        mov  mem3,$RESULT+6   //Addr_3
        itoa mem3
        mov  Str3,"Addr_3="
        add  Str3,$RESULT 
        add  Str3,#0D0A#
findon:
  find mem0,#AD#       //从Addr_0开始查找
        cmp  $RESULT,0
        jz   stop
        mov  mem0,$RESULT
  find mem0,#01C8#,40
        cmp  $RESULT,0     
  jnz  findoff
        add  mem0,40
        cmp  mem0,mem5
        ja   stop            //超过Addr_5后停止
        jmp  findon
findoff:
        bp   $RESULT
        add  mem0,40
        itoa $RESULT
        jmp  findon
stop: 
  run
@1:
        sti
        gn   eax
        cmp  $RESULT,0
        jz  @1      
  itoa eip
        mov  Str1,"Addr_1="
        add  Str1,$RESULT
        add  Str1,#0D0A#
  bpwm tmp,csize
        run
@3:
  sti
        cmp [eax],ecx
        jnz @3
  itoa eip
  mov  Str2,"Addr_2="
  add  Str2,$RESULT
  add  Str2,#0A0D#
        add  Str0,Str1
        add  Str0,Str2
        add  Str0,Str3
        add  Str0,Str4
        add  Str0,Str5
        msg  Str0
        pause

          -----------------------------------------------------------
      脚本1的使用非常简单,用OD打开要解密的软件,直接运行脚本1,第一次弹出的对话框给出了6个确定的断点.
      Themida每次加密代码都有变化,特征码很难捕获。比如要捕获的特征代码如果是 mov [eax],ecx:
  
      那么,代码 mov [eax],ecx  可以有多种变化,如:
  
  0068475C    51               push    ecx
  0068475D    813424 1F15FD3E  xor     dword ptr [esp], 3EFD151F
  00684764    8F00             pop     dword ptr [eax]
  00684766    52               push    edx
  00684767    BA 00000000      mov     edx, 0
  0068476C    01C2             add     edx, eax
  0068476E    8132 1F15FD3E    xor     dword ptr [edx], 3EFD151F
  00684774    5A               pop     edx
    
      或者
  00679700    51               push    ecx
  00679701    53               push    ebx
  00679702    BB AF61DB7F      mov     ebx, 7FDB61AF
  00679707    315C24 04        xor     dword ptr [esp+4], ebx
  0067970B    5B               pop     ebx
  0067970C    8F00             pop     dword ptr [eax]
  0067970E    8130 AF61DB7F    xor     dword ptr [eax], 7FDB61AF    
  
      
     (新改进的脚本1已经成为全自动了)
     当你把这6个断点地址写入了脚本2后(可以打开脚本2直接修改)就可以关掉OD了。
  
      2.脚本2(API修复)的使用
    ----------------------------------------------------
  //本脚本适用于Thmida 1.9.1.0版本
  
    bphwc
    bc
  
  data:
    var mem
    var mem1
    var temIAT
    var temESI
    var temAPI
    var APIstr
    var Addr_0
    var Addr_1
    var Addr_2
    var Addr_3
    var Addr_4
    var Addr_5
  
  Init:
      //用对话框中的断点值修改下列各断点,Addr_1,Addr_2的值必须单步跟踪后确定
      //只须修改这6个地址
  
    mov Addr_0,676d13     
    mov Addr_1,67763b      
    mov Addr_2,679714    
    mov Addr_3,679889             
    mov Addr_4,679cd6     
    mov Addr_5,67cc30    
     
  start:  
    esto
    esto
    bphws Addr_0,"x" 
    esto  
    bphwc Addr_0
    mov [Addr_0],#90E9#  //将jb改为jmp,去除代码扫描
   
    
    bp Addr_1     
    bp Addr_2    
    bp Addr_3    
    bp Addr_4  
    bp Addr_5    
  
  First:
    run
    cmp eip,Addr_1
    jz  A1
    cmp eip,Addr_2        
    jz  A2
    cmp eip,Addr_3
    jz  A3
    cmp eip,Addr_4
    jz  A4
    cmp eip,Addr_5
    jz  A5
    jmp  First
  
  A1:    
    mov temAPI,eax     //eax 是API函数地址
    gn temAPI         //显示函数名
    log $RESULT 
    add APIstr,"  "
    add APIstr,$RESULT_2  //恢复API函数名(INT表)
    jmp First
  A2:    
    mov temIAT,eax
    cmp  edx,10000
    ja  next
    xor  edx,80000000
    mov [eax],edx        //修复IAT表(写入序列号)
    jmp First
  next: 
    mov [eax],temAPI
    jmp First
  
  A3:
    mov mem1,eax          //eax是内存中呼叫API地址
    mov temESI,[esi]      //获取转跳标记
    jmp First
  
  A4:
    cmp temESI,AAAAAAAA
    jnz step3
    mov [mem1],#FF25#      //修复代码中转跳地址
    mov [mem1+2],temIAT   
    jmp First
  
  step3:
    mov [mem1],#FF15#      //修复代码中呼叫地址
    mov [mem1+2],temIAT
    jmp First
  
  A5:
    bc
  //---下面位置在运行脚本3后,写入OEP修复代码,若要再次用于新的程序,则应该将添加的代码删除 
    pause
  ------------------------------------------------------
      脚本2的使用更简单,当用脚本1的6个地址把本脚本中对应地址修改好后存盘,用OD再次打开该软件,运行脚本2。注意:这6个地址不能有丝毫差错!程序运行如飞,很快停止在断点Addr_5上。
  
      注意到这时堆栈项是:13FF64,而刚打开OD时栈项是13FFC4,差值是60,后面平衡堆栈(脚本3中)要用。
  
      将OD代码段转到401000开始的位置,用OD分析代码一次,你将看到所有的秘密都显示出来了。以提供的FindFile为例,转到API函数表位置(API集中转跳位置402646402736),选出代码前面没有“$-”符号的部分(本例只有3个):
      (若全部都没有“$-”符号,再用OD分析一次)
  
  00402652   .- FF25 A4304000 jmp     dword ptr [4030A4]   ;  USER32.DialogBoxParamA
  004026B2   .- FF25 48304000 jmp     dword ptr [403048]   ;  kernel32.ExitProcess
  004026DC   .- FF25 24304000 jmp     dword ptr [403024]   ;  kernel32.GetModuleHandleA
  
  0040272A   $- FF25 04304000 jmp     dword ptr [403004]
  00402730   $- FF25 00304000 jmp     dword ptr [403000]
  
      注意到,40272A、402730后面没有出现函数名称,但[403004]和[403000]中都有确定的值。用alt-M 打开Memory map,发现comdlg32.dll库是红色显示,我什么也没做,关掉Memory map后,居然正常显示了如下:(不能解释其原因)
  
  0040272A   $- FF25 04304000 jmp     dword ptr [403004]    ;  comdlg32.GetOpenFileNameA
  00402730   $- FF25 00304000 jmp     dword ptr [403000]    ;  comdlg32.GetSaveFileNameA
  
      现在打开脚本3(OEP修复),将没有“$-”符号的那3个函数的相应的代码(照原样写),如下添加在脚本3中:
  
          mov [402652],#FF25A4304000#  //<--对应 USER32.DialogBoxParamA 
    mov [4026B2],#FF2548304000#  //<--对应 kernel32.ExitProcess
    mov [4026DC],#ff2524304000#  //<--对应 kernel32.GetModuleHandleA
    mov [4030A4],77D3B144        //<--在该地址中查到的值(注意倒着写),下同
    mov [403048],7C81CAFA        
    mov [403024],7C80B731        
          bp  402652                   //设置对应的断点,下同
          bp  4026B2
          bp  4026DC
     
      为什么要写入脚本3中呢?原来程序在运行了脚本2后,Themida早已侦查到了系统内存中出现了“调试器”,若继续运行,会在运行一段时间后中止,得不到最后结果。当你在脚本3中写入了相应代码后存盘,关闭OD。
  
       3.脚本3(OEP修复)的使用
  ---------------------------------------------
  data:  
    var Addr_5
  start:
      esto
      esto
    mov Addr_5,67cc30  // <----写入由脚本1得到的Addr_5  
  
      bphws Addr_5,"x"
      esto
      bphwc
  
      //----下面位置在运行脚本2后,添加与OEP有关的断点处代码,若要再次用于新的程序,则应该将全部代码删除
  
    mov [402652],#FF25A4304000#
    mov [4026B2],#FF2548304000#
    mov [4026DC],#ff2524304000#
    mov [4030A4],77D3B144
    mov [403048],7C81CAFA
    mov [403024],7C80B731
          bp  402652
          bp  4026B2
          bp  4026DC
          bpwm 404000,1000                  //404000的确定是根据402000是代码区,403000是资源数据区  
  pause
  ------------------------------------------------------
       脚本3的作用实际上就是将OD运行到底(Addr_5的值一定要根据脚本1得到的修改)。按F9,由于在脚本中添加了如上代码,程序将中断在上面4个断点之一上。添加这些代码的作用就是恢复被VM虚拟的API(在入口代码段中),且运行后在将在堆栈中揭示其秘密。
       核对无错误后,用OD再次打开软件,加载脚本3,程序停在Addr_5上。按F9,OD中断在
  004026DC   .- FF25 24304000 jmp     dword ptr [403024]   ;  kernel32.GetModuleHandleA
       在堆栈中看到:
  0013FF7C   0066E2F0  /CALL 到 GetModuleHandleA
  0013FF80   00000000  \pModule = NULL
  
       这就是入口的第1个API调用。记下后,再F9,中断在VM虚拟机代码段中:
  00B9CD7E    F3:A4           rep     movs byte ptr es:[edi], byte ptr [esi]
  
       下面的状态条中显示:
       ecx = 00000004
       ds:[esi]=[003E1FF8]=00
       es:[edi]=[00404000]=00
       原来是向[00404000]中写入代码,代码值就是当前堆栈中的 003E1FF8 中的值。404000就是GetModuleHandleA 句柄地址。
       继续F9,中断在
  00402652    - FF25 A4304000 jmp     dword ptr [4030A4]              ;  USER32.DialogBoxParamA
       堆栈中显示:
  0013FF6C   0066E2FC  /CALL 到 DialogBoxParamA
  0013FF70   00400000  |hInst = 00400000
  0013FF74   00000064  |pTemplate = 64
  0013FF78   00000000  |hOwner = NULL
  0013FF7C   00401B92  |DlgProc = FindFile.00401B92
  0013FF80   00000000  \lParam = NULL
  
       这就是入口的第2个API调用,其参数堆栈中显示非常清楚。因为程序将立即进入DialogBoxParamA,直到关闭窗口后才退出,下面就交替F9或alt-F9,直到窗口出现。(会反复多次按F9或alt-F9,这是因为脚本中设置了“bpwm 404000,1000”的原因),我不知道怎样在运行中清除它?
       关闭程序窗口,程序中断在
  004026B2    - FF25 48304000 jmp     dword ptr [403048]              ;  kernel32.ExitProcess
       堆栈中出现
  0013FF7C   0066E309  /CALL 到 ExitProcess
  0013FF80   00000000  \ExitCode = 0
       请暂时不要关闭OD,整个入口代码都清楚了。将OD代码转到40261C处(乱码开始位置),逐条汇编如下:
  
       汇编语言                 对应代码
       push  0                  6A00
       call  4026DC             E8B9000000
       mov   [404000],eax       A300404000
       push  0                  6A00
       push  401B92             68921B4000
       push  0                  6A00
       push  64                 6A64
       push  [404000]           FF3500404000
       call  402652             E814000000
       push  0                  6A00
       call  4026B2             E86D000000
       int3                     CC               <--最后添上一个int3,让其返回系统
  
       4.脚本2的最后完善
     ---------------------------------
       现在打开脚本2,在标签A5:的bc后面写入(添加)如下代码:
       (1)修复OEP(完整抄录OD上汇编后出的2进制码):
       mov  [40261C],#6A00E8B9000000A3004040006A0068921B40006A006A64FF3500404000E8140000006A00E86D000000CC#
       (2)为平衡堆栈,实现对OEP的转跳,继续写入:(前面记录过栈项的差值=60)
       mov  [Addr_5],#81C460000000B81C26400050C3#
        (即对应下列汇编的二进制代码:
         add   esp,60
         mov   eax,40261C
         push  eax
         retn      )
       (3)再写入如下代码,作用是将API函数名称写入适当空白处(如403600)减轻dump后的录入文字工作。
       mov  [403600],APIstr 
       sti
       sti
       sti
       sti      //4个单步   
       (4)写完后存盘,关闭OD,再次打开OD,加载脚本2,程序停在OEP处。若按F9,程序运行良好。
       至此,Thmida 1.9.1.0加密的软件完美解密!
  
        三、破解思路整理
        三个脚本,翻来复去地运行,有点头晕,整理思路:
       运行脚本1,得到6个断点地址--->写入脚本2,运行脚本2得到几个“无关联函数”将其信息写入脚本3,并设置相应断点--->运行脚本3,从堆栈中获取OEP入口代码信息并回写入脚本2---->运行脚本2,实现完美解密。
  
        四、后记
        1.本文的方法适用于Thmida 1.8---1.9的各种版本。1.8以前的版本我没有看过,1.9.1.0以后的也没有看过,很难说通吃各种版本,但对于大多数被Themida加密的程序应该是没有问题的。(试验得不多,若有例外,研究后改进)其实我毫无保留地给出了我破解的详细思路和作法,让有兴趣者可以在此基础上加以发展,写出Themida脱壳机。(网上有个Themida脱壳机,不知什么版本,也根本不能运行)
        2.对于用VC++编写的程序,运行脚本3不会有太好的结果,原因是没有“$-”符号的函数太多,大多是无用的(VC-6编辑器几乎将MFC42D.DLL、MSVCRTD.dll等库中函数全部装载,不管你调用不调用)而windows下的API又很少使用,但VC++的入口代码又具有相对固定的模式,甚至可以nop掉一堆SEH的设置代码,程序对入口的堆栈长度设置(如:add esp,-6C)也不敏感(参考我《对themida1855加密VC++程序的完美脱壳》一文)对于用VC++编写的程序在运行脚本1后,运行脚本2一次,获取入口地址后,在脚本2的A5:标签后直接添加如下代码: 
  
      mov  [4xxxxx],APIstr                             //4xxxxx表示找一段空白,写入函数名称      
      mov  [Addr_5],#81C460000000B8xxxx4x0050C3#       //xxxx4x入口地址反向写入
      mov  [4xxxxx],#558BEC6AFF90909090909090909090909090909090909090909090909083C4945356578965E8C745FC000000006A02#                       //代码长度由现场决定,4xxxxx表示OEP入口地址(乱码开始地址),添加的代码几乎无须改动
      sti
      sti
      sti
      sti   
      将脚本2存盘一次,再次运行它,当你具有一定经验后,可能会得到满意的结果。
        3.请注意,当须要把三个脚本用于新的程序时,请一定将前一个程序在脚本2、脚本3中添加的代码删除,否则可能有不希望的结果发生。
        4.通过三个脚本解密的程序,可以dump了,但dump后的程序还要加工才能运行。如修改IID导入表,恢复INT表,还原IAT表中数据,瘦身等,这些是PE文件基本知识,不涉及破解知识,不在此讨论。
  
        谢谢你耐心地读完本文!希望能对你有所帮助。    
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2008年09月22日 23:10:50

上传的附件 temp.rar[附件请到论坛下载:http://bbs.pediy.com/showthread.php?t=73257]

  • 标 题:脚本1已经改进.
  • 作 者:wulje
  • 时 间:2008-09-23 11:43:44

附件中的脚本1是个手动版,现已经改进为自动版了,即运行后就出现6个准确断点,脚本如下:
    //Themida 1.9.1.0的断点设置脚本(改进版)
data:
                var memory
                var csize
                var tmp
                var temp
  var tmpbp
  var mem
  var mem0
                var mem1
  var mem2
  var mem3
   var mem4
  var mem5
  var Str0
  var Str3
  var Str4
  var Str5
  var Str1
                var Str2
star:
                gmi eip,CODEBASE
                mov  memory,$RESULT
                gmi eip,CODESIZE
  mov csize,$RESULT
                add csize,memory  
  find memory,#0000000000000000000000000000000000000000000000#
  mov tmp,$RESULT
  bphws tmp,"w"
        esto
  esto
  esto
  bphwc tmp
  sto
  find memory,#0000000000000000000000000000000000000000000000#
  mov tmp,$RESULT
                sub csize,tmp
                find memory,#909090909090909090909090909090909090#
  mov temp,$RESULT+8
  bphws temp,"w"
  mov  tmpbp,eip
  run
  cmp  eip,tmpbp+2
                jnz  next
                run
  next:
  bphwc
                mov  Str0,"断点地址:"
                add  Str0,#0D0A#
  mov  mem,eip
  mov  mem4,eip           //eip=Addr_4
  itoa eip
  mov  Str4,"Addr_4="
                add  Str4,$RESULT
                add  Str4,#0A0D#
                find mem4,#83BD????????000F8497000000#
                mov  mem5,$RESULT       //Addr_5
                itoa mem5 
                mov  Str5,"Addr_5="
                add  Str5,$RESULT 
                sub  mem,4000 
  find mem,#83BD????????640F82??020000#
                mov  mem0,$RESULT+7    //Addr_0
                itoa mem0
                add  Str0,"Addr_0="
                add  Str0,$RESULT 
                add  Str0,#0D0A#
                find mem0,#C1C003#
                find $RESULT,#0385????7409#,40
                mov  mem3,$RESULT+6   //Addr_3
                itoa mem3
                mov  Str3,"Addr_3="
                add  Str3,$RESULT 
                add  Str3,#0D0A#
findon:
  find mem0,#AD#       //从Addr_0开始查找
           cmp  $RESULT,0
                jz   stop
                mov  mem0,$RESULT
  find mem0,#01C8#,40
                cmp  $RESULT,0     
  jnz  findoff
                add  mem0,40
                cmp  mem0,mem5
                ja   stop            //超过Addr_5后停止
           jmp  findon
findoff:
                bp   $RESULT
                add  mem0,40
                itoa $RESULT
                jmp  findon
stop: 
                run
@1:
               sti
               gn   eax
               cmp  $RESULT,0
               jz  @1      
               itoa eip
               mov  Str1,"Addr_1="
               add  Str1,$RESULT
               add  Str1,#0D0A#
               bpwm tmp,csize
               run
@3:
               sti
               cmp [eax],ecx
               jnz @3
               itoa eip
               mov  Str2,"Addr_2="
               add  Str2,$RESULT
               add  Str2,#0A0D#
               add  Str0,Str1
               add  Str0,Str2
               add  Str0,Str3
               add  Str0,Str4
               add  Str0,Str5
               msg  Str0
               pause

  • 标 题:脚本1已经改进.
  • 作 者:wulje
  • 时 间:2008-09-23 11:58:32

附件中的脚本1是个手动版,现已经改进为自动版了,即运行后就出现6个准确断点,脚本如下:
    //Themida 1.9.1.0的断点设置脚本(改进版)
data:
                var memory
                var csize
                var tmp
                var temp
  var tmpbp
  var mem
  var mem0
                var mem1
  var mem2
  var mem3
   var mem4
  var mem5
  var Str0
  var Str3
  var Str4
  var Str5
  var Str1
                var Str2
star:
                gmi eip,CODEBASE
                mov  memory,$RESULT
                gmi eip,CODESIZE
  mov csize,$RESULT
                add csize,memory  
  find memory,#0000000000000000000000000000000000000000000000#
  mov tmp,$RESULT
  bphws tmp,"w"
        esto
  esto
  esto
  bphwc tmp
  sto
  find memory,#0000000000000000000000000000000000000000000000#
  mov tmp,$RESULT
                sub csize,tmp
                find memory,#909090909090909090909090909090909090#
  mov temp,$RESULT+8
  bphws temp,"w"
  mov  tmpbp,eip
  run
  cmp  eip,tmpbp+2
                jnz  next
                run
  next:
  bphwc
                mov  Str0,"断点地址:"
                add  Str0,#0D0A#
  mov  mem,eip
  mov  mem4,eip           //eip=Addr_4
  itoa eip
  mov  Str4,"Addr_4="
                add  Str4,$RESULT
                add  Str4,#0A0D#
                find mem4,#83BD????????000F8497000000#
                mov  mem5,$RESULT       //Addr_5
                itoa mem5 
                mov  Str5,"Addr_5="
                add  Str5,$RESULT 
                sub  mem,4000 
  find mem,#83BD????????640F82??020000#
                mov  mem0,$RESULT+7    //Addr_0
                itoa mem0
                add  Str0,"Addr_0="
                add  Str0,$RESULT 
                add  Str0,#0D0A#
                find mem0,#C1C003#
                find $RESULT,#0385????7409#,40
                mov  mem3,$RESULT+6   //Addr_3
                itoa mem3
                mov  Str3,"Addr_3="
                add  Str3,$RESULT 
                add  Str3,#0D0A#
findon:
  find mem0,#AD#       //从Addr_0开始查找
           cmp  $RESULT,0
                jz   stop
                mov  mem0,$RESULT
  find mem0,#01C8#,40
                cmp  $RESULT,0     
  jnz  findoff
                add  mem0,40
                cmp  mem0,mem5
                ja   stop            //超过Addr_5后停止
           jmp  findon
findoff:
                bp   $RESULT
                add  mem0,40
                itoa $RESULT
                jmp  findon
stop: 
                run
@1:
               sti
               gn   eax
               cmp  $RESULT,0
               jz  @1      
               itoa eip
               mov  Str1,"Addr_1="
               add  Str1,$RESULT
               add  Str1,#0D0A#
               bpwm tmp,csize
               run
@3:
               sti
               cmp [eax],ecx
               jnz @3
               itoa eip
               mov  Str2,"Addr_2="
               add  Str2,$RESULT
               add  Str2,#0A0D#
               add  Str0,Str1
               add  Str0,Str2
               add  Str0,Str3
               add  Str0,Str4
               add  Str0,Str5
               msg  Str0
               pause