首页
社区
课程
招聘
实践内存注册机变算法注册机之明码篇
发表于: 2006-11-4 21:00 47106

实践内存注册机变算法注册机之明码篇

2006-11-4 21:00
47106
    日前,帮朋友分析某软件算法,找到注册码很简单,因为是明码的,但是人家要求写个算法注册机,稍微看了下,大致是用GetSystemTime是取GTM时间参数,然后跟机器码经过一系列运算得到注册码,所以注册码也是动态的。写个算法注册机挺麻烦的。所以想做个内存注册机给对方,哪知人家说还要替别人算号的,况且该系列的算法模块都是一样的,不喜欢KEYMAKE做的内存注册机。
想起以前在论坛好像碰到过情况,搜索论坛,看了几篇有关进程、线程的文章后,又看了几位前辈写的LOADER源码,自己也动手实践了下。

原理非常简单,写个类似补丁的东西,创建一个进程启动目标程序,在机器码和注册码处插入INT3断点,然后调试进程,当停在机器码位置时,恢复代码,写入新机器码,通过原来软件的算法流程得到新的注册码。读出注册码就可以了。
为了更象算法注册机,我加入了注册机的界面。

先分析一下软件:

0046CDE8  |.  8B83 08030000 MOV EAX,DWORD PTR DS:[EBX+308]
0046CDEE  |.  E8 71D0FCFF   CALL <test.@TControl@GetText>            ;  取出机器码
0046CDF3  |.  8B45 E8       MOV EAX,DWORD PTR SS:[EBP-18]            ;  机器码
0046CDF6  |.  50            PUSH EAX                                 ;  EAX为机器码
0046CDF7  |.  8D55 E4       LEA EDX,DWORD PTR SS:[EBP-1C]
0046CDFA  |.  8B83 08030000 MOV EAX,DWORD PTR DS:[EBX+308]
0046CE00  |.  E8 5FD0FCFF   CALL <test.@TControl@GetText>
0046CE05  |.  8B55 E4       MOV EDX,DWORD PTR SS:[EBP-1C]            ;  机器码
0046CE08  |.  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]             ;  注册码
0046CE0B  |.  59            POP ECX                                  ;  00E52224
0046CE0C  |.  E8 DFE8FFFF   CALL <test.sub_46B6F0>                   ;  关键算法,跟入
0046CE11  |.  84C0          TEST AL,AL
0046CE13  |.  0F84 EE000000 JE <test.loc_46CF07>                     ;  爆破

================== 关键算法
0046B6F0 >/$  55            PUSH EBP                                
0046B6F1  |.  8BEC          MOV EBP,ESP
0046B6F3  |.  83C4 F0       ADD ESP,-10
0046B6F6  |.  53            PUSH EBX
0046B6F7  |.  56            PUSH ESI
0046B6F8  |.  33DB          XOR EBX,EBX
0046B6FA  |.  895D F0       MOV DWORD PTR SS:[EBP-10],EBX
0046B6FD  |.  894D F4       MOV DWORD PTR SS:[EBP-C],ECX             ;  机器码
0046B700  |.  8955 F8       MOV DWORD PTR SS:[EBP-8],EDX
0046B703  |.  8945 FC       MOV DWORD PTR SS:[EBP-4],EAX             ;  假注册码
0046B706  |.  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
0046B709  |.  E8 8A92F9FF   CALL <test.@@LStrAddRef>
0046B70E  |.  8B45 F8       MOV EAX,DWORD PTR SS:[EBP-8]
0046B711  |.  E8 8292F9FF   CALL <test.@@LStrAddRef>
0046B716  |.  8B45 F4       MOV EAX,DWORD PTR SS:[EBP-C]
0046B719  |.  E8 7A92F9FF   CALL <test.@@LStrAddRef>
0046B71E  |.  33C0          XOR EAX,EAX
0046B720  |.  55            PUSH EBP
0046B721  |.  68 D1B74600   PUSH <test.sub_46B7D1>
0046B726  |.  64:FF30       PUSH DWORD PTR FS:[EAX]
0046B729  |.  64:8920       MOV DWORD PTR FS:[EAX],ESP
0046B72C  |.  33DB          XOR EBX,EBX
0046B72E  |.  8D4D F0       LEA ECX,DWORD PTR SS:[EBP-10]
0046B731  |.  8B55 F4       MOV EDX,DWORD PTR SS:[EBP-C]             ;  机器码
0046B734  |.  8B45 F8       MOV EAX,DWORD PTR SS:[EBP-8]
0046B737  |.  E8 20FEFFFF   CALL <test.sub_46B55C>                   ;  算法2,跟入
0046B73C  |.  A1 2CFA4600   MOV EAX,DWORD PTR DS:[46FA2C]
0046B741  |.  0FB600        MOVZX EAX,BYTE PTR DS:[EAX]
0046B744  |.  8B4D F0       MOV ECX,DWORD PTR SS:[EBP-10]            ;  算法2结果
0046B747  |.  8A4C01 CF     MOV CL,BYTE PTR DS:[ECX+EAX-31]          ;  结果放入ECX,ECX就是注册码
0046B74B  |.  8B75 FC       MOV ESI,DWORD PTR SS:[EBP-4]

由此可见,0046CDF6中的EAX指向的是机器码,0046B747中的ECX指向的是注册码。知道这两点就可以写LOADER了,下面是完整代码:

.586
.model flat, stdcall  
option casemap :none  
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib
include comdlg32.inc
includelib comdlg32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
IDD_DLG1                equ 1000
IDC_NAME                equ 1001
IDC_CODE                equ 1002
IDC_OK                  equ 1005
IDC_ABOUT               equ 1006
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
BREAK_POINT1   equ 0046CDF6h ;第一个断点
BREAK_POINT2   equ 0046B747h ;第二个断点
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DlgProc proto :HWND,:UINT,:WPARAM,:LPARAM
GetKey  proto
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
MsgboxText    db '    -=Author: langxang=-',0dh
              db ' -=Email:langxang@126.com=-',0
MsgboxCaption db '关于',0
MsgBoxText1    db '请输入远程机器码!',0
MsgBoxCaption1 db '提示',0
MsgBoxText2    db '请置于TEST.EXE软件的根目录!',0
MsgBoxText3    db '退出进程!',0
FileName db ".\test.exe",0
Startup STARTUPINFO <>
processinfo PROCESS_INFORMATION <>

TotalInstruction dd 0
AppName db "test",0
int3    db 0cch   
BUFFER  db 8 dup(?)
value   db 8 dup(?)
MCode   db 8 dup(?)   
oldbyte1 db 50h
oldbyte2 db 8Ah
szFormat db "%X",0

.data?
buffer db 512 dup(?)
startinfo STARTUPINFO <>
pi PROCESS_INFORMATION <>
DBEvent DEBUG_EVENT <>
context CONTEXT <>
uExitCode     dd ?
hInstance     HINSTANCE ?
hDlg          HINSTANCE ?
UserID        db 80 dup (?)
Serial        db 80 dup (?)

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
start:
  invoke GetModuleHandle,NULL
       mov hInstance,eax
  invoke DialogBoxParam,hInstance,IDD_DLG1,NULL,addr DlgProc,NULL
  invoke ExitProcess,0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
        mov eax,uMsg
  .if     eax==WM_CLOSE
       invoke EndDialog,hWin,0
  .elseif eax==WM_INITDIALOG
       push hWin
       pop  hDlg     
  .elseif eax==WM_COMMAND
          mov eax,wParam
             .if eax==IDC_OK               
                invoke GetDlgItemText,hDlg,IDC_NAME,addr UserID,Sizeof UserID                                                        
                   .if eax==0
                     invoke MessageBox,hDlg,addr MsgBoxText1,addr MsgBoxCaption1,MB_OK
                   .elseif  
                     invoke GetKey
                     invoke SetDlgItemText,hDlg,IDC_CODE,addr value
                   .endif
             .elseif eax==IDC_ABOUT
                invoke MessageBox,hDlg,addr MsgboxText,addr MsgboxCaption,MB_OK
             .endif            
  .else
    mov eax,FALSE
    ret
  .endif
  mov eax,TRUE
  ret
DlgProc endp

GetKey proc  
       pushad
;********************************************************************
; 创建进程
;********************************************************************         
       invoke CreateProcess, addr FileName, NULL, NULL, NULL, FALSE, DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS, NULL, NULL, addr startinfo, addr pi
    .if    !eax
        invoke MessageBox,hDlg,addr MsgBoxText2,addr MsgBoxCaption1,MB_OK
        invoke ExitProcess,NULL
    .endif
;********************************************************************
; 调试进程
;********************************************************************
   .while TRUE
      invoke WaitForDebugEvent, addr DBEvent, INFINITE
      .if DBEvent.dwDebugEventCode==EXIT_PROCESS_DEBUG_EVENT
          invoke MessageBox, 0, MsgBoxText3, addr  MsgBoxCaption1, MB_OK+MB_ICONINFORMATION
          .break
;********************************************************************
; 如果进程开始,则将两个断点地址的代码改为INT3中断
;********************************************************************
      .elseif DBEvent.dwDebugEventCode==CREATE_PROCESS_DEBUG_EVENT           
          invoke  WriteProcessMemory,pi.hProcess,BREAK_POINT1,addr int3,1,NULL       ;插入INT3
          invoke  WriteProcessMemory,pi.hProcess,BREAK_POINT2,addr int3,1,NULL       ;插入INT3   
;********************************************************************
; 中断触发的异常事件,并进入安全模式读写状态
;********************************************************************   
      .elseif DBEvent.dwDebugEventCode==EXCEPTION_DEBUG_EVENT
          .if DBEvent.u.Exception.pExceptionRecord.ExceptionCode==EXCEPTION_BREAKPOINT
          mov context.ContextFlags, CONTEXT_FULL
             invoke GetThreadContext, pi.hThread, addr context
;********************************************************************
; 如果在机器码处中断,则恢复原来的代码,并写入新的机器码
;********************************************************************              
             .if     context.regEip == BREAK_POINT1+1
              dec     context.regEip
              invoke  WriteProcessMemory,pi.hProcess,BREAK_POINT1,addr oldbyte1,1,NULL    ;恢复代码
              mov eax,context.regEax                                                      ;机器码在EAX中
              invoke  WriteProcessMemory,pi.hProcess,eax,addr UserID,16h,NULL             ;读入22位机器码
              invoke  SetThreadContext,pi.hThread, addr context                           ;设置生效
              ;invoke ReadProcessMemory,pi.hProcess,context.regEax,addr BUFFER,16h,NULL   ;用于检测修改的机器码是否已经生效
              ;invoke  MessageBox,0, addr BUFFER,addr AppName, MB_OK+MB_ICONINFORMATION              
                 
;********************************************************************
; 如果在注册码处中断,则恢复原来的代码,并读出注册码
;********************************************************************                                                     
            .elseif  context.regEip == BREAK_POINT2+1
              dec     context.regEip
              invoke WriteProcessMemory,pi.hProcess,BREAK_POINT2,addr oldbyte2,1,NULL     ;恢复代码
              invoke ReadProcessMemory,pi.hProcess,context.regEcx,addr value,14h,NULL     ;注册码在ECX中
              ;invoke SetDlgItemText,hDlg,IDC_CODE,addr value                              ;输出到注册码框
              invoke SetThreadContext,pi.hThread, addr context  
              invoke TerminateProcess,pi.hProcess,uExitCode                               ;强行退出
              .break
            .endif
            invoke ContinueDebugEvent,    DBEvent.dwProcessId, DBEvent.dwThreadId, DBG_CONTINUE
            .continue           
          .endif
                          
      .endif
      invoke ContinueDebugEvent, DBEvent.dwProcessId, DBEvent.dwThreadId,   DBG_EXCEPTION_NOT_HANDLED
   .endw
;********************************************************************
; 结束线程
;********************************************************************
   invoke CloseHandle,pi.hProcess
   invoke CloseHandle,pi.hThread   
    popad
    ret
GetKey endp
end start   

文本框2中得到的就是利用原程序算法流程计算后得到的注册码,怎么样,俨然一个算法注册机。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (57)
雪    币: 443
活跃值: (200)
能力值: ( LV9,RANK:1140 )
在线值:
发帖
回帖
粉丝
2
太强了~~~~学习!
2006-11-4 21:26
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
佩服佩服,虽然我有点一知半解
2006-11-4 21:37
0
雪    币: 179
活跃值: (131)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
4
学习学习,这可以算是两篇精华了
2006-11-4 21:53
0
雪    币: 207
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
好东西,收藏
2006-11-4 23:12
0
雪    币: 405
活跃值: (10)
能力值: ( LV9,RANK:1130 )
在线值:
发帖
回帖
粉丝
6
晕倒。又是汇编~~~
2006-11-5 00:00
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
支持汇编
汇编写的东西其实还简单些
我看那些C++的,都有一些古怪的符号
2006-11-5 10:14
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
第一楼的明码用本机机器码2254069508-58980863这样的,算法程序运行了N久也没得出注册码

还有机器码数字多了也不行555555-888888

不懂ING
2006-11-5 16:35
0
雪    币: 127
活跃值: (1785)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
学习!~
2006-11-5 16:54
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
好文章,学习啊~~
2006-11-5 22:06
0
雪    币: 269
活跃值: (51)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
很不错的一种方法,学习收藏了.
2006-11-5 23:24
0
雪    币: 224
活跃值: (75)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
12
楼主什么时候放个KEYMAKE来造福我这样不会编程得小菜阿.
2006-11-6 07:54
0
雪    币: 4
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
学习 很受启发
2006-11-6 07:59
0
雪    币: 219
活跃值: (56)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
14
学习~~~~LZ什么时候能不能把KEYMAKE放出来分享一下~~~~~~
2006-11-6 10:18
0
雪    币: 208
活跃值: (51)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
同楼上,如果遇见加壳的 如何判断是否解压完成好插入INT3呢?
2006-11-6 13:11
0
雪    币: 2601
活跃值: (2115)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
按照这个原理,比较简单的程序一般都可以处理。但是如果防INT3或者防内存补丁的程序一般要先处理这些ANTI。另外对于有些压缩壳加壳的软件,可以采用启动后迅速挂起或者等待几秒挂起的方法。对于那些ANTI很厉害的壳程序,这个是没有用的。
如果你编程技术了得,可以模拟刘前辈的KEYMAKE写个注册机生成器:

可以提供???谢谢!
2006-11-6 21:06
0
雪    币: 3519
活跃值: (4047)
能力值: (RANK:215 )
在线值:
发帖
回帖
粉丝
17
帖子里代码怎么编译通不过??

高,希望指点代码问题,这样以后偶就用这个做模版了,高!!!!
2006-11-6 23:36
0
雪    币: 3519
活跃值: (4047)
能力值: (RANK:215 )
在线值:
发帖
回帖
粉丝
18
laomms 跑哪去了,快回来,看看我的问题。

你帖子里的代码编译后执行没反应啊。
2006-11-7 10:40
0
雪    币: 191
活跃值: (205)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
19
强帖,学习了
2006-11-7 11:19
0
雪    币: 560
活跃值: (354)
能力值: ( LV13,RANK:1370 )
在线值:
发帖
回帖
粉丝
20
最初由 china 发布
laomms 跑哪去了,快回来,看看我的问题。

你帖子里的代码编译后执行没反应啊。


因为没有贴资源脚本:

#define IDD_DLG1 1000
#define IDC_GRP1 1007
#define IDC_NAME 1001
#define IDC_CODE 1002
#define IDC_STC1 1003
#define IDC_STC2 1004
#define IDC_OK 1005
#define IDC_ABOUT 1006
#include "Res/keygenDlg.rc"
IDD_DLG1 DIALOGEX 6,5,238,52
CAPTION "loader for crackeme"
FONT 8,"MS Sans Serif",0,0
STYLE 0x10CA0880
EXSTYLE 0x00000001
BEGIN
  CONTROL "",IDC_NAME,"Edit",0x50010000,64,9,104,15,0x00000200
  CONTROL "",IDC_CODE,"Edit",0x50010000,64,29,104,15,0x00000200
  CONTROL "机器码:",IDC_STC1,"Static",0x50000201,8,11,34,9
  CONTROL "  注册码:",IDC_STC2,"Static",0x50000000,8,31,53,9
  CONTROL "打开",IDC_OK,"Button",0x50010000,180,9,48,15
  CONTROL "关于",IDC_ABOUT,"Button",0x50010000,180,29,48,15
  CONTROL "",IDC_GRP1,"Button",0x50000007,4,0,170,48
END
0 ICON DISCARDABLE "ico.ico"

源文件,RadASM直接打开:
上传的附件:
2006-11-7 11:55
0
雪    币: 3519
活跃值: (4047)
能力值: (RANK:215 )
在线值:
发帖
回帖
粉丝
21
最初由 laomms 发布
因为没有贴资源脚本:

#define IDD_DLG1 1000
#define IDC_GRP1 1007
#define IDC_NAME 1001
........


哼哼,打倒laomms一百次。



不懂汇编真郁闷。我是个大笨蛋。
2006-11-7 12:07
0
雪    币: 300
活跃值: (412)
能力值: ( LV9,RANK:410 )
在线值:
发帖
回帖
粉丝
22
学习了,好文章。keymaker,喜欢……
2006-11-7 13:46
0
雪    币: 3519
活跃值: (4047)
能力值: (RANK:215 )
在线值:
发帖
回帖
粉丝
23
004E8282    8995 8CFEFFFF   mov     [ebp-174], edx                   ; EMAIL在EDX里,位数不确定
004E8288    C745 B8 0000000>mov     dword ptr [ebp-48], 0
004E828F    8B95 8CFEFFFF   mov     edx, [ebp-174]
004E8295    8D4D B4         lea     ecx, [ebp-4C]
004E8298    FF15 08134000   call    near [401308]                    
004E829E    8B45 BC         mov     eax, [ebp-44]
004E82A1    50              push    eax
004E82A2    8D4D B4         lea     ecx, [ebp-4C]
004E82A5    51              push    ecx
004E82A6    E8 45A4FAFF     call    MyAB.004926F0
004E82AB    8BD0            mov     edx, eax                         ; 注册码eax,12位

以上内容修改到代码里,不能正确获得注册码。

注册码是根据email地址计算得来的。程序为繁体程序,运行后窗口句柄名称为
“我的??簿 v2.7.5”

另外:1、主程序为UPX加壳的VB程序。2、怎么确定输入的email的长度让程序接受并修改到内存?

上面的改如何修改代码?

请laomms指点。
2006-11-7 14:14
0
雪    币: 560
活跃值: (354)
能力值: ( LV13,RANK:1370 )
在线值:
发帖
回帖
粉丝
24
最初由 china 发布
004E8282 8995 8CFEFFFF mov [ebp-174], edx ; EMAIL在EDX里,位数不确定
004E8288 C745 B8 0000000>mov dword ptr [ebp-48], 0
004E828F 8B95 8CFEFFFF mov edx, [ebp-174]
004E8295 8D4D B4 lea ecx, [ebp-4C]
004E8298 FF15 08134000 call near [401308]
........


    EMAIL在EDX里,你要读取中断后内存中EDX的值mov eax,context.regEdx, EMAIL位数不确定可以读取你输入的EMAIL的长度,压入该长度就可以了。
    如果是加壳的程序,这个补丁是无效,因为捕获的异常未必是设置的断点,有时候要对程序自己设置的异常先进行处理。 而且加壳后,代码都是加密的,所以得必须保证所设的断点的内存空间已经还原完毕,不然可能导致程序在还原过程中把所设的断点清除,甚至还有可能使程序还原出无用的代码,致使程序运行失败。有的还会对INT3进行检测。
    对于壳的强度不怎么样的软件,应该可以通过修改DRx设置硬件断点的方法,也不用修改CC代码和还原原来的代码那么复杂了。如果有时间,下次写个类似的程序。
2006-11-7 15:05
0
雪    币: 3519
活跃值: (4047)
能力值: (RANK:215 )
在线值:
发帖
回帖
粉丝
25
最初由 laomms 发布
EMAIL在EDX里,你要读取中断后内存中EDX的值mov eax,context.regEdx, EMAIL位数不确定可以读取你输入的EMAIL的长度,压入该长度就可以了。
如果是加壳的程序,这个补丁是无效,因为捕获的异常未必是设置的断点,有时候要对程序自己设置的异常先进行处理。 而且加壳后,代码都是加密的,所以得必须保证所设的断点的内存空间已经还原完毕,不然可能导致程序在还原过程中把所设的断点清除,甚至还有可能使程序还原出无用的代码,致使程序运行失败。有的还会对INT3进行检测。
对于壳的强度不怎么样的软件,应该可以通过修改DRx设置硬件断点的方法,也不用修改CC代码和还原原来的代码那么复杂了。如果有时间,下次写个类似的程序。


感谢+支持+期待。
2006-11-7 15:27
0
游客
登录 | 注册 方可回帖
返回
//