能力值:
( LV7,RANK:110 )
|
-
-
29 楼
楼主,你想破解的话,先准备工具,需要的工具ollydbg, PE Exolorer
Cheat Engine和VS2010,以及楼主的加壳程序!
先用VS2010建立一个控制台工程,
工程代码如下
#include "stdafx.h"
#include <Windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
_asm int 3//这个代码一定需要,这个代码调用时会加载调试器,用来在不同调试器中使程序断在我想要的位置
while(1)
{
while(::MessageBox(0,L"是否记录到导出表?",L"Test",MB_YESNO)==IDYES)
{
return 0;
}
}
return 0;
}
然后打开工程设置,将工程设置为固定基地址,以及取消地址虚拟化,取消VC代码的折叠优化,不做以上设置,就会影响破解!
解释一下为什么要设置死循环,就是需要减少程序的启动次数!
好,将工程编译为Release版本,我们调试一下,没问题,正常调用!
用加密程序加密吧!加密时选择IAT加密,以及代码段加密,选择出现提示,以便我们附加需要的调试器,而程序中的INT 3指令,是帮助我们的调试器定位在我们的代码的,其余的我们都不
选,以免影响我们的破解!
//我们准备好已经加密过的程序以后,用PE Exolorer打开未加密的文件,查看一下导出表地址,我这里是00402224h 大小50h ,导出函数链表地址为00402000h 记录下来,备用
然后直接运行加密后的程序,如果加密无误,会弹出崩溃提示,这时我们附加VC的调试器上去,会看到VC弹出提示,遇到我们先前设置的断点!
断点后面的代码如下
00401003 int 3 //这里就是我们设置的断点,VC附加无误后会断在这里!
00401004 mov eax,1
00401009 test eax,eax
0040100B je 0040102E
0040100D push 4
0040100F push 4020F4h
00401014 push 402100h
00401019 push 0
0040101B call dword ptr ds:[4020A4h]//当运行到这里时,记录一下括号里面的值,我这里是4020A4h,然后找到导出表开始的地
记录值之后,停止VC调试,
打开Cheat Engine 61,然后运行加密过的程序,等弹出提示的时候,用CE附加它,然后选择手动添加指针,然后填入00402000
,添加指针之后,在指针列表上单击右键,选择找出是谁改写了这个指针,然后继续运行程序,之后CE会记录到,到底是什么地方改写了这个指针,也就是IAT的指针
接着打开CE的记录,单击第一个记录(一般是第一个的),然后点击 显示反汇编工具,就会自动找到改写这个IAT的地址,我这里是0040AFC8,
0040AFB0 - mov eax,[00407140] : [0041B000]
0040AFB5 - lea ecx,[esi+esi*4]
0040AFB8 - mov edx,[eax+ecx*4]
0040AFBB - mov eax,[004169C0] : [00260000]
0040AFC0 - mov ecx,[eax+esi*4]
0040AFC3 - mov eax,[004169D0] : [00400000]
0040AFC8 - mov [eax+edx],ecx
这时我们观察一下寄存器的值,
EAX=00400000
EBX=00270000
ECX=006B0000
EDX=00002000
ESI=0000000F
EDI=00000000
ESP=0018FF74
EBP=0018FF88
发现什么情况没有?
eax+edx=00402000 EAX就是模块基地址,那么EDX就是相对偏移 这么说这里的EDX保存的是原导入表地址啦?赶紧保存
什么情况00402000不是原导入表地址么?这里怎么进行了赋值操作?
ECX的值哪里来的?
mov ecx,[eax+esi*4]这里来的!
这句代码一看就知道类似 Addr[i]=值
那EAX的值就应该等于Addr的地址啦!
mov eax,[004169C0] : [00260000]
这里赋值EAX
看004169C0指向的地址,这像一个变量(经验判断的)
接着,在CE中添加地址,勾选指针类型,偏移量,我们写0
然后重启被加密的程序,然后附加CE,找到刚才添加的指针,右键,选择找出是谁访问了这个指针,弹出的对话框中选择第一个
然后,回到被加密程序中,单击确定,这时CE就记录了是谁访问了这个变量!
在弹出的代码列表中,选择第一个(一般都是第一个的)
然后按旁边的反汇编按钮,定位到改写这个变量的地址
我这里是0040B3BD
得到获取IAT地址的指令在那之后,
接下来就只能靠OD了,打开OD,用OD加载被加密程序之后,定位到0040B3BD
然后下断点,接下来,凭经验,找到填写这个地址的函数头,在那里下断点,
然后按F9运行,接着被加密程序会弹出消息框,我们单击确定,然后会陷入我们OD下的断点中,
接着,仔细了哦!别漏了,这里要有重要的事情发生了,仔细看寄存器,以及OD的显示
运行到0040b213处时,发生了什么事情?ECX寄存器里,居然得到了解密之后的模块文件名,
留一个题,你们自己分析,在上面已经运行过的代码中,可以分析出,加密的密钥是什么!
你们自己去分析吧!我就不去分析了直接修改代码,让解密以后,再进行加密混淆的代码无法运行!
模块文件名,我们得到了,接下来,继续运行
运行到0040B369处时候,我们得到了什么?居然是调用GetProceAddress哈哈,这就好办了,第一个参数是模块地址,第二个就是函数名!这就好办了,不用说,记录!
我们继续调试,当GetProceAddress返回时,居然看见了一个让我惊喜的东西,在0040B378处,看到了xor eax,15151515,哈哈,加密混淆指令,明显是使用GetProceAddress返回的地址与
15151515进行异或,当然不允许了,直接用NOP填充,接下来
函数调用了VirtualAlloc申请了内存,用来干嘛呢?接下来,有一大堆的指令,如果没有EAX寄存器的指令,我们直接忽略,接下来到了
0040B3A4 指令处,注意啊!注意看ECX的值,以及指令,
MOV DWORD PTR DS:[EDX*4+ECX],EAX这个指令很熟悉吧?不就是和前面赋值IAT的指令相似么?
再看看作为基地址的ECX的内容,ECX居然等于00260000,这不是前面的用于赋值给IAT的变量么?原来在这里,嘿嘿,不用说的,直接吧正确的地址给写回去,也就是GetProceAddress返回的
地址,写回去,把0040B396到0040B39F用NOP填充掉,把0040B36F到0040B388全部用NOP填充掉,下面,就是一些清除原导入表的操作,不用说的,果断NOP掉,别忘了保存一下函数与导入表的
关系,以及需要写入导出表的地址,否则,破解就白做了,
然后就用OD保存修改,
再用OD加载修改之后的程序,定位到OEP的最后的RET指令,这时在堆栈顶端,就可以看见原来的OEP,果断保存!
到此,我们得到了,模块名,函数名,以及对应的需要写入的IAT的地址:第一个IAT函数地址就是 00402000+0*4,第二个就是00402000+1*4,第三个就是00402000+2*4,以此类推,就能填写
IAT了,有了模块名,和函数名,自己写一个模块名与函数名的链表,然后就将IAT指向原IAT就行!
破解与获取IAT,以及获取OEP的方法,大家可以看看,哈哈有了原程序的IAT信息,我们自己构建IAT了,就不用麻烦楼主的壳给我恢复IAT了,也就直接过了你的老师的花指令!
好累啊!接下来的自己构建IAT的事,嘿嘿留给楼主自己了,看电脑久了,头大了!
|
能力值:
( LV7,RANK:110 )
|
-
-
41 楼
内核不好玩的,玩内核你小心了,给你个忠告,玩内核编程千万要注意,你得先准备几块硬盘!我玩内核编程时,报废了三块硬盘,以及一块显卡,BOSS被我弄坏了一次,系统嘛就不知道弄坏了多少次,嘿嘿,还是RING3好,绝对不会弄坏硬件!另外,你的壳我的VC 不支持,我还是贴出来吧!你自己能看懂多少就多少了,另外壳程序,我早就写过了,而且是半汇编的
代码如下// SetHardWare.cpp : 定义应用程序的入口点。
//
#include "stdafx.h"
#include "SetHardWare.h"
typedef
ULONG
(NTAPI
*PRtlNtStatusToDosError)(
ULONG Status
);
//#include "../../testbase/Memory/Memory.h"
//PRtlNtStatusToDosError RtlNtStatusToDosError=(PRtlNtStatusToDosError)::GetProcAddress(::GetModuleHandle(L"Ntdll.dll"),"RtlNtStatusToDosError");
#include "../../BPHookFunction/BPHookFunction/BPHookFunction.h"
//#include "../../testbase/Memory/Memory.h"
#define MAX_LOADSTRING 100
typedef ULONG (WINAPI *pfnRtlDispatchException)(PEXCEPTION_RECORD pExcptRec,CONTEXT * pContext);
pfnRtlDispatchException m_fnRtlDispatchException=(pfnRtlDispatchException)::GetProcAddress(::GetModuleHandleA("ntdll"),"KiUserExceptionDispatcher");;
// 全局变量:
HINSTANCE hInst; // 当前实例
TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
int APIENTRY _tWinMain2(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow);
// 此代码模块中包含的函数的前向声明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain2(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow);
LONG WINAPI MyTopUnhandledExceptionFilter(
struct _EXCEPTION_POINTERS *ExceptionInfo
);
// extern "C" __declspec(dllimport) ULONG NTAPI RtlNtStatusToDosError(
// _In_ LONG Status
//);
BOOL RtlDispatchException(PEXCEPTION_RECORD pExcptRec,CONTEXT * pContext)
{
// 返回TRUE,这个异常我已经处理好了,继续运行程序
// 返回FALSE,这个异常不是我的,找别人处理去
MessageBox(0,L"DDDD",L"DDSADS",0);
return 1;
}
ULONG WINAPI _RtlDispatchException( PEXCEPTION_RECORD pExcptRec,CONTEXT * pContext )
{
if(RtlDispatchException(pExcptRec,pContext)) return 1;
return m_fnRtlDispatchException(pExcptRec,pContext);
}
BOOL HookSystemSEH()
{
m_fnRtlDispatchException=(pfnRtlDispatchException)::GetProcAddress(::GetModuleHandleA("ntdll"),"KiUserExceptionDispatcher");
return 0;
// return SetInlineHook((PVOID*)&m_fnRtlDispatchException,_RtlDispatchException);
}
DWORD Address = 0,EndAddress = 0;
LPVOID Data = 0;
DWORD IsCall = 0;
HANDLE VectoredHandler = 0;
VOID WINAPI RegFilter()
{
PVOID Data = (PVOID)Address;
if(RtlNtStatusToDosError==0) exit(0);
#ifndef _DEBUG
if(::IsDebuggerPresent()) return ;
#else
#endif
VectoredHandler=AddVectoredExceptionHandler(1,MyTopUnhandledExceptionFilter);
if(VectoredHandler==0) exit(0);
}
int WINAPI Show()
{
return ::MessageBox(0,L"我差,居然有调试器,请结束调试器!",L"调试器",16);
}
__declspec(naked)int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
_asm
{
mov edi,edi//WINAPI 约定调用方式 这里的一大堆指令,其实就是一个意思,就是jmp _tWinMain2
push ebp
mov ebp, esp
push eax
lea eax,dword ptr[Error]
mov Address,eax
lea eax,dword ptr[End]
mov EndAddress,eax
mov eax,110
xor ebx ,ebx
pop eax
mov esp,ebp
pop ebp
mov eax,110
push eax
push dword ptr[Next]
push RegFilter
ret
Next: pop eax
Error: _asm idiv ebx
call Show
ret 16
End:
#ifdef _DEBUG
ret 16
#else
call dword ptr[DebugBreak]
push Error+2
#endif
ret
ret 16
}
}
LONG WINAPI MyTopUnhandledExceptionFilter(
struct _EXCEPTION_POINTERS *ExceptionInfo
)
{
PVECTORED_EXCEPTION_HANDLER Handler=(PVECTORED_EXCEPTION_HANDLER)VectoredHandler;
// return Handler(ExceptionInfo);
WCHAR Buffer[32]={0};
DWORD ExceptionCode=RtlNtStatusToDosError(ExceptionInfo->ExceptionRecord->ExceptionCode);
// ExceptionCode=::BaseNtStatusToDosError(ExceptionCode);
//_asm int 3 c0000094
//wsprintf(Buffer,L"%x",ExceptionCode);
//MessageBox(0,Buffer,L"Text",0);
//if(IsCall==1)
if(IsCall==2) return 0;
if(ExceptionInfo->ExceptionRecord->ExceptionCode==0x80000003)
{
if(ExceptionInfo->ContextRecord->Eax==120)
//if(EndAddress==(DWORD)ExceptionInfo->ExceptionRecord->ExceptionAddress)
{
ExceptionInfo->ContextRecord->Eax=119;
ExceptionInfo->ContextRecord->Esp=ExceptionInfo->ContextRecord->Esp+4;
ExceptionInfo->ContextRecord->Eip=(DWORD)Data;
return EXCEPTION_CONTINUE_EXECUTION;
}
return 0;
}
if(ExceptionCode==998)
{
//if(ExceptionInfo->ExceptionRecord->ExceptionAddress==(PVOID)Data)
// {
//if(IsCall==2) return 0;
if(ExceptionInfo->ExceptionRecord->ExceptionAddress==Data)
{
memset(Data,0,16);
VirtualFree(Data,16,MEM_DECOMMIT);
if(ExceptionInfo->ContextRecord->Eax==119)
{
IsCall=2;
ExceptionInfo->ContextRecord->Eip=(DWORD)_tWinMain2;
return EXCEPTION_CONTINUE_EXECUTION;
}
}
// }
}
if(ExceptionInfo->ExceptionRecord->ExceptionCode==0xc0000094)
{
//ExceptionInfo->ExceptionRecord->
if(ExceptionInfo->ExceptionRecord->ExceptionAddress==(PVOID)Address)
{
if(ExceptionInfo->ContextRecord->Eax==110)
{
Data=VirtualAlloc(0,16,MEM_COMMIT, PAGE_READWRITE);
//::IsDebuggerPresent()
BOOL IsDebug= ::IsDebuggerPresent();
#ifndef _DEBUG
// if(::IsDebuggerPresent()) return ;
#else
IsDebug=FALSE;
#endif
if(IsDebug)
{
#ifndef _DEBUG
ExceptionInfo->ContextRecord->Eip=ExceptionInfo->ContextRecord->Eip+2;
#else
ExceptionInfo->ContextRecord->Eip=(DWORD)_tWinMain2;
#endif
//return EXCEPTION_CONTINUE_EXECUTION;
RemoveVectoredExceptionHandler(VectoredHandler);
return EXCEPTION_CONTINUE_EXECUTION;
}
#ifdef _DEBUG
ExceptionInfo->ContextRecord->Eip=(DWORD)_tWinMain2;
RemoveVectoredExceptionHandler(VectoredHandler);
return EXCEPTION_CONTINUE_EXECUTION;
#endif
if(Data==0)
{
//exit(0);
ExceptionInfo->ContextRecord->Eip=ExceptionInfo->ContextRecord->Eip+2;
}else
{
CONTEXT lpContext={0};
IsCall=1;
memset(Data,0xcc,16);
ExceptionInfo->ContextRecord->Eax=120;
ExceptionInfo->ContextRecord->Eip=EndAddress;
}
}
}
return EXCEPTION_CONTINUE_EXECUTION;
}
return 0;
}
int APIENTRY _tWinMain2(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此放置代码。
// _asm int 3
MSG msg;
HACCEL hAccelTable;
// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_SETHARDWARE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SETHARDWARE));
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// 函数: MyRegisterClass()
//
// 目的: 注册窗口类。
//
// 注释:
//
// 仅当希望
// 此代码与添加到 Windows 95 中的“RegisterClassEx”
// 函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,
// 这样应用程序就可以获得关联的
// “格式正确的”小图标。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SETHARDWARE));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_SETHARDWARE);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// 函数: InitInstance(HINSTANCE, int)
//
// 目的: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // 将实例句柄存储在全局变量中
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意绘图代码...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
实际入口点为_tWinMain2,VC,为我们连接的入口点是_tWinMain,至于为什么入口点是_tWinMain,因为这是一个例子,不用更改mainCRTStartup的,这里做演示就已经够了!
|