首页
社区
课程
招聘
[原创]内存注册机的工作原理及masm源码
发表于: 2007-6-5 15:22 31109

[原创]内存注册机的工作原理及masm源码

2007-6-5 15:22
31109
[编程工具]masm32(9.00)+RadAsm2.2.0.9
[调试工具]OD1.10
[调试平台]WinXP/SP2

  先说明一下,我编写这个内存注册机只是为了学习一点程序的调试原理,它的实用性不说也罢,因为现的软件保护谁都知道,想这么容易取得注册码,门都没有,这也许正是刘健英放弃KeyMake的原因吧。我不想,也没有能力去步他的后尘,只是好奇,玩玩而已。
  内存注册机实际是个超小的调试器,以调试的方式打开目标软件进程,在特定的地址设置 int 3 断点,程序运行到断点处被挂起,这个时候就可以用 ReadProcessMemory 或 GetThreadContext 函数取得目标软件特定内存或特定寄存器中的内容,显示出来就好了。只是前面提到的地址、寄存器等只有你跟踪了目标软件的注册算法后才会得到。根据注册算法的不同,注册机中的某些代码也可能要调整,所以我的代码对不会编程的人来说就是1000%的垃圾。
  有些软件加了壳,不过我终于想出办法来对付它了,有壳我照样可以断下来,取到我想要的数据。杀毒软件对我的注册机也不感兴趣,大概是太臭了吧~O~。

内存注册机.Asm文件:

.386
.model flat, stdcall  ;32 bit memory model
option casemap :none  ;case sensitive

include 内存注册机.inc

.code

start:
        invoke InitCommonControls
        invoke GetRegKey
    invoke ExitProcess,0

;########################################################################

GetRegKey proc uses edi esi
    LOCAL @ThreadConText:CONTEXT
    LOCAL @StartInfo:STARTUPINFO
        LOCAL @DBGEvent:DEBUG_EVENT
        LOCAL @TmpCode,@BakCode
        LOCAL @FullPath[512]:byte

        invoke GetCommandLine
        lea    esi,@FullPath
        invoke lstrcpy,esi,eax
        mov    edi,esi
        xor    edx,edx
        xor    ecx,ecx
        cld
       .while TRUE  ;找最后一个“\”
               lods   byte ptr[esi]
               inc    ecx
               .break .if !al
               .continue .if al!='\'
               mov    edx,ecx  ;记下最后一个“\”的位置
        .endw
        add    edi,edx
        invoke lstrcpy,edi,addr szEXEName  ;生成绝对路径,否则由CreateProcess创建的进程可能会出问题

        invoke GetStartupInfo,addr @StartInfo
        invoke CreateProcess,NULL,addr @FullPath,NULL,NULL,FALSE,DEBUG_PROCESS+DEBUG_ONLY_THIS_PROCESS,NULL,NULL,addr @StartInfo,addr PI
        .if !eax  ;创建debugee进程失败的话提示、结束
              invoke MessageBox,NULL,addr szMsgErr,NULL,MB_ICONERROR
              jmp ENDPROC
        .endif

       .while TRUE
              invoke WaitForDebugEvent,addr @DBGEvent,INFINITE  ;等待调试事件的发生
              .break .if @DBGEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT  ;你退出了我也就退出吧!

              .if  TimesBreak  ;debugee执行第一条指令之前我们不必做无用功
                      .if TimesBreak<BREAKFLAG  ;已经取过注册码了吗?
                            mov   eax,@BakCode
                            .if al!=byte ptr[OldCode]  ;如果debugee加了壳,而且还没正确设置int 3断点
                              invoke ReadProcessMemory,PI.hProcess,BreakPoint,addr @TmpCode,sizeof @TmpCode,NULL
                                  mov    eax,@TmpCode
                                  .if al==byte ptr[OldCode]  ;壳已经解码完毕,可以设断点了
                                         mov  @BakCode,eax   ;记住,我们在此已经役过断点了,用它作标志,还要用它恢复现场
                                       invoke WriteProcessMemory,PI.hProcess,BreakPoint,addr BreakCode,sizeof BreakCode,NULL  ;设断点
                                  .endif
                            .endif
                      .endif
              .endif

             .if @DBGEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT
                    .if @DBGEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
                          .if TimesBreak  ;已经不止一次发生int 3中断的话
                                 invoke CloseHandle,PI.hThread ;释放旧hThread的内存
                                 invoke OpenThread,THREAD_GET_CONTEXT or THREAD_QUERY_INFORMATION,FALSE,@DBGEvent.dwThreadId  ;由ThreadID得到hThread 想依此来解决多线程问题,会不会有问题,请高人指点
                                 mov PI.hThread,eax ;保存备用

                                 mov @ThreadConText.ContextFlags,CONTEXT_FULL    ;访问所有的寄存器
                                 invoke GetThreadContext,PI.hThread,addr @ThreadConText  ;取debugee的数据
                                 dec @ThreadConText.regEip  ;EIP已经指向int 3中断的下一条代码了,让它重新指向int 3
                                 mov ecx,@ThreadConText.regEip  ;取debugee的EIP
                                 .if ecx==BreakPoint  ;是我们要断下的地方吗?是就取出数据,并恢复现场
                                        invoke WriteProcessMemory,PI.hProcess,ecx,addr @BakCode,sizeof @BakCode,NULL  ;恢复debugee原来的代码
                                        invoke SetThreadContext,PI.hThread,addr @ThreadConText  ;修改debugee的EIP,让其继续运行
   
                                    invoke GetModuleHandle,NULL
                                    lea edx,@ThreadConText    ;把此结构的地址传给窗口,以便于显示
                                    invoke DialogBoxParam,eax,IDD_DLGMAIN,NULL,addr DlgProc,edx   ;弹出窗口,输出注册码
                                    mov TimesBreak,BREAKFLAG  ;设置标志,已经取过注册码了
                                 .endif
                          .else  ;如果debugee未加壳,就此两句可以设好断点,若加了壳就不起作用了,因为壳会修改掉我们的修改
                               invoke ReadProcessMemory,PI.hProcess,BreakPoint,addr @BakCode,sizeof @BakCode,NULL
                                 invoke WriteProcessMemory,PI.hProcess,BreakPoint,addr BreakCode,sizeof BreakCode,NULL
                          .endif
                         inc TimesBreak
                    .endif
                    mov eax,DBG_CONTINUE
                    jmp @F
              .endif
              mov eax,DBG_EXCEPTION_NOT_HANDLED
@@:
              invoke ContinueDebugEvent,@DBGEvent.dwProcessId,@DBGEvent.dwThreadId,eax
       .endw

       invoke CloseHandle,PI.hProcess
       invoke CloseHandle,PI.hThread
ENDPROC:
    ret

GetRegKey endp

DlgProc proc uses ebx hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

    mov eax,uMsg
    .if eax==WM_INITDIALOG
                mov     ebx,lParam
            assume    ebx:ptr CONTEXT  ;ebx作为CONTEXT类型指针使用
                ;要显示什么数据,怎么显示,那你就去分析debugee的注册算法吧,我这里只是示例
                ;invoke ReadProcessMemory,PI.hProcess,RegKeyAddr,addr Buffer,sizeof Buffer,NULL   ;从特定内存地址中取注册码

                invoke wsprintf,addr Buffer,addr szFmt,[ebx].regEax  ;从特定寄存器中取注册码
                invoke SetDlgItemText,hWin,IDC_REGKEY,addr Buffer

                assume    ebx:nothing
    .elseif eax==WM_CLOSE
        invoke EndDialog,hWin,0
    .else
        mov    eax,FALSE
        jmp    @F
    .endif
    mov    eax,TRUE
@@:
    ret

DlgProc endp

end start

内存注册机.Inc文件:

include windows.inc
include kernel32.inc
include user32.inc
include Comctl32.inc
include shell32.inc

includelib kernel32.lib
includelib user32.lib
includelib Comctl32.lib
includelib shell32.lib

DlgProc            PROTO    :HWND,:UINT,:WPARAM,:LPARAM
GetRegKey               PROTO

.const

IDD_DLGMAIN        equ 101
IDC_REGKEY        equ 1003
BREAKFLAG               equ 100000h

.data
szFmt                   db '%1X',0
szMsgErr                db '本注册机必须与下面的软件放在同一目录内:',0dh  ;中间不要有其它变量定义
szEXEName               db '例子.exe',0   ;换成要注册的软件可执行文件名

BreakPoint              dd 0401131h  ;可以改成要设断点的地址
OldCode                 db 050h      ;BreakPoint处的第一字节内容,帮我们判断壳是否操作完毕,完毕才能设断点
;RegKeyAddr             dd 40305ch   ;注册码在debugee中的存放地址

BreakCode               db 0CCh,90h,90h,90h  ;最好别改动
TimesBreak              dd 0  ;最好别改动

;#########################################################################
.data?

PI                      PROCESS_INFORMATION<>
Buffer                  db 256dup(?)

************************************************************************************************************
我这个贴子只说了内存注册机的一般原理,未做成通用模板,因此需要会编程的使用者视具体情况添加或改动代码,比如多线程、多次中断在同一地址等。后面有人跟贴提到这两个问题。对于多线程问题,我想了个对策,代码见上文,调试了没问题。对于第二个问题,最好去读一下我转贴的《Win32调试API教程》之第三部分。我的大致思路是:
  1.第一次正确发生int3中断时,设为单步模式,为的是后面有机会再写入断点。也可以设硬件断点,那是另一套思路了。

  2.在单步事件到来时,重写入断点代码,暂不单步了
      .if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
        (前面的判断代码此处略)
        mov @ThreadConText.ContextFlags, CONTEXT_CONTROL
        invoke GetThreadContext, PI.hThread, addr @ThreadConText
        or @ThreadConText.regFlag,100h ;设为单步模式,为的是后面有机会再写入断点
        invoke WriteProcessMemory,PI.hProcess,ecx,addr @BakCode,sizeof @BakCode,NULL  ;恢复debugee原来的代码
        invoke SetThreadContext,PI.hThread,addr @ThreadConText  ;修改debugee的EIP,让其继续运行
        inc TimesBreak
        (后面的代码此处略)
      .elseif DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_SINGLE_STEP ;int3中断后紧接着单步一次
        invoke WriteProcessMemory,PI.hProcess,BreakPoint,addr BreakCode,sizeof BreakCode,NULL ;再次写入中断代码,对付同一地址多次中断。


  马上要放假了,比较忙,没有时间详细设计和调试,只能这样了,算是抛砖引玉吧。假期我要好好休息一下,不会来这里了(要扔砖头的尽管扔,反正我不知道^O^)。希望收假后能看到更好的解决方法。
********************************************************************************************************************

附件中是asm源码和例子程序

[课程]Linux pwn 探索篇!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (60)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
认真学习,感谢分享
2007-6-5 16:18
0
雪    币: 89
活跃值: (151)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
压缩有问题,下载不完整
2007-6-5 16:37
0
雪    币: 202
活跃值: (77)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
不错的东西,谢谢楼主,收下了
2007-6-5 16:48
0
雪    币: 2899
活跃值: (1753)
能力值: ( LV9,RANK:850 )
在线值:
发帖
回帖
粉丝
5
Radasm即将大面积流行,不管压缩是否有问题,都要顶一顶!晚上再来下载,可以吗?
2007-6-5 16:50
0
雪    币: 156
活跃值: (48)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
个人觉得内存注册机还是很有前途的,不光在crack
2007-6-5 17:04
0
雪    币: 1844
活跃值: (35)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
先顶了再看,谢了
2007-6-5 18:12
0
雪    币: 2595
活跃值: (2110)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感谢共享!!!!
2007-6-5 18:32
0
雪    币: 325
活跃值: (97)
能力值: ( LV13,RANK:530 )
在线值:
发帖
回帖
粉丝
9
怎么喜欢用ASM哦。。不好点嘛。
2007-6-5 18:35
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
10
楼主肯定想不到我找这方面的东西找了多久的。
真是....太感激了。我抢
多谢贡献。。
2007-6-5 18:55
0
雪    币: 219
活跃值: (1634)
能力值: ( LV9,RANK:410 )
在线值:
发帖
回帖
粉丝
11
学习再学习,谢谢LZ提供的好文章!
2007-6-5 19:40
0
雪    币: 1919
活跃值: (901)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
12
楼主文章不错,最近几篇都仔细研究过,继续拜读~~~
2007-6-5 20:15
0
雪    币: 359
活跃值: (419)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
顶一个,强.
2007-6-5 22:23
0
雪    币: 538
活跃值: (460)
能力值: ( LV9,RANK:290 )
在线值:
发帖
回帖
粉丝
14
不懂。。以前学过的汇编是16位的。。。还是支持下。。。
2007-6-5 23:35
0
雪    币: 296
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
strrchr.....能看懂 ...谢谢楼主分享
2007-6-6 00:40
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
刚上来就遇到这等好东东,谢谢楼主
2007-6-6 03:24
0
雪    币: 314
活跃值: (15)
能力值: ( LV12,RANK:410 )
在线值:
发帖
回帖
粉丝
17
我下载试了一下,没问题,怎么会不完整??
2007-6-6 07:29
0
雪    币: 1969
活跃值: (46)
能力值: (RANK:550 )
在线值:
发帖
回帖
粉丝
18
好文章,学习!
2007-6-6 08:50
0
雪    币: 243
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
看了《Win32调试API教程》,有效果了吧
2007-6-6 09:37
0
雪    币: 707
活跃值: (1301)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
20
不错 ........
2007-6-6 10:38
0
雪    币: 2899
活跃值: (1753)
能力值: ( LV9,RANK:850 )
在线值:
发帖
回帖
粉丝
21
回来了,顶一顶
2007-6-6 10:39
0
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
22
楼主近视程度……
2007-6-6 13:18
0
雪    币: 314
活跃值: (15)
能力值: ( LV12,RANK:410 )
在线值:
发帖
回帖
粉丝
23
阁下此话怎讲???是说我没远见吗?哈哈,愿闻其详。
2007-6-6 15:27
0
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
24
是说字体太大……
2007-6-6 15:28
0
雪    币: 244
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
25
看不懂...
2007-6-6 15:32
0
游客
登录 | 注册 方可回帖
返回
//