能力值:
( LV2,RANK:10 )
|
-
-
146 楼
这本电子书是用active ebook做的。前面15章免费,后面需要密码。想破解,但没破了。求助破解。
我用的是softice和winhex,但是没有成功。
电子书地址
http://www.live-share.com/files/274285/most-personal-comp.rar.html
清华的有关破解的BBS如下:
发信人: yjl (会挽雕弓如满月,西北望,射天狼。), 信区: Crack
标 题: 破解active ebook制作的电子书
发信站: BBS 水木清华站 (Tue Apr 27 16:27:11 2004), 站内
上个学期破解了用active ebook compiler 4.22做的几个电子书(其实它们都是完全一样的
方法),当时简单记下了注册码,不想这次重装系统之后注册码居然都是错误的。无奈之
下,只好重新破解,顺便写了一个“注册机”。破解的经过并不难,只是觉得写“注册机”的方
法值得和大家共享(keymake的内存注册机应该也是用这种方法);同时,个人觉得这种电
子书应该是免费的,因此公开这篇文章也就心安理得了。
以破解“秦堤居士”(加个引号是因为鄙视之,呵呵,看看他的网页就会有同感)的二十五史
3上(文件名25book301.exe)为例:
在注册对话框中输入注册码goodyjl,确定,不要点击跳出的错误消息框,打开WINHEX,选择
编辑RAM,选择25sbook301的主要内存,CTRL+F查找刚才输入的密码goodyjl。在0012f2b0处
找到了,记下这个地址。(我偷懒了,没用softice干这件事)
现在切到softice中,输入bpmd 0012f2b0 rw if(dword(*0012f2b0)==646f6f67),646f6f67
就是goodyjl在内存中的第一个双字的值(在softice中用“? 'good'”看看)。现在回到25boo
k301程序中,点击注册,输入注册码goodyjl,确定,softice拦截在子函数41f312内,分析
它的汇编码,没什么有用的信息,F12返回到它的调用者41DC61,在41DC61处设置断点。F5,
中断在41DC61处,现在分析它的代码:在41dc89处调用GetPrivateStringA,"64812-030501-
154943-18","PasswordE",4639cc,"goodyjl",400h,"ANS2000.INI"。呵呵,原来程序从ANS2
000.ini读入密码到4639cc,并验证它。跟踪下去,在41DC89处(也就是起先我们从41f312
按F12回到的地方)F10跳过,发现4639cc变成了goodyjl,很明显程序在INI文件中存储的是加
密后的注册码,41f312就是解密函数。继续跟踪,在4177d9处,程序调用439db1("3DU297PS
WR","goodyjl"),"3DU297PSWR"就是我们要找的密码了。
push eax
push dword ptr[ebp-10]
call 00439db1
写“注册机”,说是注册机,其实是从内存中“取出”注册码。从上面的分析知道电子书检查注
册码的地方是4177d9处,方法是简单的字符串比较;那么可以写个程序在4177d9处中断程序,
读出正确的注册码*(ebp-10)。我用windows的debug api实现了它,下面是代码,很粗糙,我
只给了简单的注释:
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <tchar.h>
#define ADDRESS 0x4177d9 //中断的地址
#define CODE 0xE8, 0xD3, 0x25, 0x02, 0x00
//4177d9处的代码,用它来判断是否是电子书文件
#define DATALEN 50 //定义需要读出的数据数量
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow) {
OPENFILENAME ofn;
DEBUG_EVENT de;
PROCESS_INFORMATION pi;
CONTEXT context;
STARTUPINFO sui;
char lpstrFile[MAX_PATH]="";
BYTE lpCode[]={CODE};
BYTE lpBuffer[]={CODE};
DWORD nSize;
ZeroMemory(&ofn, sizeof ofn);
ofn.lStructSize = sizeof ofn;
ofn.lpstrFilter = _T("可执行文件\0*.exe\0");
ofn.lpstrFile = lpstrFile;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrTitle = _T("请选择使用Active Ebook Compiler 4.22编译的电子书");
//首先要求用户选择电子书
if (GetOpenFileName(&ofn)) {
GetStartupInfo(&sui);
//创建进程
if (!CreateProcess(ofn.lpstrFile, NULL, NULL, NULL, FALSE,
DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &sui, &pi)) {
MessageBox(NULL, _T("无法创建进程!"), _T("错误"),
MB_ICONERROR | MB_OK);
return 1;
}
//这一步实际上是等待进程创建的完成
if (!WaitForDebugEvent(&de, 120)) {
MessageBox(NULL, _T("无法调试进程!"), _T("错误"),
MB_ICONERROR | MB_OK);
return 1;
}
//先判断是否是ebook
if (!ReadProcessMemory(pi.hProcess, (LPVOID)ADDRESS, lpBuffer,
sizeof(lpBuffer), &nSize) || nSize!=sizeof(lpBuffer)) {
MessageBox(NULL, _T("无法读进程!"), _T("错误"),
MB_ICONERROR | MB_OK);
return 1;
}
for (DWORD i=0; i<nSize; i++) {
if(lpCode[i]!=lpBuffer[i]) {
MessageBox(NULL,
_T("不是Active Ebook Compiler 4.22编译的电子书!"),
_T("错误"), MB_ICONERROR | MB_OK);
return 1;
}
}
//将CC写入4177d9处,这样程序执行到那里就会发生异常,
//我们就可以控制它了。cc实际上是int 3指令。
for (i=0; i<nSize; i++) {
lpBuffer[i] = 0xCC; //int 3指令
}
if (!WriteProcessMemory(pi.hProcess, (LPVOID)ADDRESS, lpBuffer,
sizeof(lpBuffer), &nSize) || nSize!=sizeof(lpBuffer)) {
MessageBox(NULL, _T("无法写进程!"), _T("错误"),
MB_ICONERROR | MB_OK);
return 1;
}
//让电子书继续运行继续
if (!ContinueDebugEvent(de.dwProcessId, de.dwThreadId,
DBG_CONTINUE) ) {
MessageBox(NULL, _T("无法继续调试!"), _T("错误"),
MB_ICONERROR | MB_OK);
return 1;
}
//等待调试事件
while (WaitForDebugEvent(&de, INFINITE)) {
//是int 3中断吗
if (de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) {
//确定是我们设置的断点
if ((DWORD)de.u.Exception.ExceptionRecord.
ExceptionAddress==0x4177d9) {
LPVOID lpAddress;
char lpBuf[DATALEN];
//调用GetThreadContext以获得ebp寄存器的值
context.ContextFlags = CONTEXT_CONTROL;
if (!GetThreadContext(pi.hThread, &context)) {
MessageBox(NULL, _T("无法读线程!"),
_T("错误"), MB_ICONERROR | MB_OK);
return 1;
}
//ebp-0x10处放的是注册码的地址
lpAddress = (LPVOID)(context.Ebp - 0x10);
if (!ReadProcessMemory(pi.hProcess, lpAddress,
&lpAddress, 4, &nSize)) {
MessageBox(NULL, _T("无法读进程!"),
_T("错误"), MB_ICONERROR | MB_OK);
return 1;
}
//读注册码
if (!ReadProcessMemory(pi.hProcess, lpAddress,
&lpBuf, DATALEN, &nSize)) {
MessageBox(NULL, _T("无法读进程!"),
_T("错误"), MB_ICONERROR | MB_OK);
return 1;
}
//恢复进程原来的代码
if (!WriteProcessMemory(pi.hProcess, (LPVOID)ADDRESS,
lpCode, sizeof(lpCode), &nSize)
|| nSize!=sizeof(lpCode)) {
MessageBox(NULL, _T("无法写进程!"), _T("错误"),
MB_ICONERROR | MB_OK);
return 1;
}
//将注册码放到剪切板
HGLOBAL hMem=GlobalAlloc(GMEM_MOVEABLE
|GMEM_DDESHARE , strlen(lpBuf)+1);
char *ptr = (char*)GlobalLock(hMem);
strcpy(ptr, lpBuf);
GlobalUnlock(hMem);
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_TEXT, hMem);
CloseClipboard();
strcat(lpBuf, "(已拷贝到剪切板)");
MessageBox(NULL, lpBuf, _T("成功取得注册码"),
MB_ICONINFORMATION | MB_OK);
//重新打开进程
CreateProcess(ofn.lpstrFile, NULL, NULL, NULL,
FALSE, 0, NULL, NULL, &sui, &pi);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
}
//继续被调试进程
if (!ContinueDebugEvent(de.dwProcessId, de.dwThreadId,
DBG_CONTINUE) ) {
MessageBox(NULL, _T("无法继续调试!"), _T("错误"),
MB_ICONERROR | MB_OK);
return 1;
}
}
}
return 1;
}
|