-
-
[原创]一个hijack的实例
-
发表于: 2022-8-20 23:27 5051
-
分享一个hijack实例
by Fpc
对于逆向者而言,找到关键点固然令人兴奋,兴奋之后怎样利用却是有多个选择。比如数据解密类,可以硬肛算法,找到所有的参数,再写一个脱机工具。而有时你不想那么掉头发,那么劫持是一个可以接受的方式,将程序流程拦下来,将明文保存下来。这方面aheadlib提供了基础框架。
本例既是如此,利用version库实现目的,自由度很大。以下是代码,没有新的知识点,这个思路可参考借鉴。
分享一个hijack实例
by Fpc
对于逆向者而言,找到关键点固然令人兴奋,兴奋之后怎样利用却是有多个选择。比如数据解密类,可以硬肛算法,找到所有的参数,再写一个脱机工具。而有时你不想那么掉头发,那么劫持是一个可以接受的方式,将程序流程拦下来,将明文保存下来。这方面aheadlib提供了基础框架。
本例既是如此,利用version库实现目的,自由度很大。以下是代码,没有新的知识点,这个思路可参考借鉴。
/
/
nversion.cpp : Defines the entry point
for
the DLL application.
/
/
/
/
modified on the base of aheadlib
-
code
/
/
/
/
for
XXXXX ver XXXX, by Fpc
/
/
/
/
首先请原谅糟糕的代码水平 T_T
/
/
/
/
用途:
/
/
某软件解密的步骤是先读取文件,用复杂的算法得到中间结果,此中间结果生成后调用一个call完成解密和解压缩,本劫持用于保存生成的结果。
/
/
利用点:
/
/
在解密call完成后劫持代码,跳到我们的修改处,取得文件名信息,建立目标文件夹,建立目标文件,写文件,关文件,恢复现场,返回
/
/
修改难点:
/
/
原文件空间很有限,并且程序中的api数量有限,diy是利用起来不方便、找罪受
/
/
利用的优势:
/
/
劫持时机可以选择,对于代码量、api调用没限制,都是你自己可以编写的。
/
/
可利用的劫持时机:
/
/
比如采用version库,在被载入时通过peb
-
> ldr搜寻一下,此例中发现是幸运的,version加载后,目标dll已经加载完毕,可以对其patch了。注意要先使目标地址可写。
/
/
如果此时目标dll还没加载怎么办,需要多一个环节,先hook GetCommandLineA
/
W,主程序运行时一般dll都加载了,此时再去找目标dll,打补丁。(这是从一个补丁文件中学来的)
/
/
基本思路:
/
/
在内存中出现明文时并且提供了相关长度、文件路径等信息后,让代码跳到version我们自己编写的空间myapi中,取得这些信息,并生成保存新文件所需要的信息,建立文件夹(不需要判断是否成功),
/
/
建立文件,取得保存文件的信息,写文件,关闭文件,恢复现场,运行被破坏的指令,恢复到原代码处继续运行。
/
/
好处是在version空间内,写什么代码不受限制
/
/
#include "stdafx.h"
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
头文件
#include <Windows.h>
#include <stdio.h>
/
/
#include <psapi.h>
#include <tlhelp32.h>
#include <string>
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
导出函数
#pragma comment(linker, "/EXPORT:GetFileVersionInfoA=_AheadLib_GetFileVersionInfoA,@1")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoByHandle=_AheadLib_GetFileVersionInfoByHandle,@2")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExW=_AheadLib_GetFileVersionInfoExW,@3")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeA=_AheadLib_GetFileVersionInfoSizeA,@4")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExW=_AheadLib_GetFileVersionInfoSizeExW,@5")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeW=_AheadLib_GetFileVersionInfoSizeW,@6")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoW=_AheadLib_GetFileVersionInfoW,@7")
#pragma comment(linker, "/EXPORT:VerFindFileA=_AheadLib_VerFindFileA,@8")
#pragma comment(linker, "/EXPORT:VerFindFileW=_AheadLib_VerFindFileW,@9")
#pragma comment(linker, "/EXPORT:VerInstallFileA=_AheadLib_VerInstallFileA,@10")
#pragma comment(linker, "/EXPORT:VerInstallFileW=_AheadLib_VerInstallFileW,@11")
#pragma comment(linker, "/EXPORT:VerLanguageNameA=_AheadLib_VerLanguageNameA,@12")
#pragma comment(linker, "/EXPORT:VerLanguageNameW=_AheadLib_VerLanguageNameW,@13")
#pragma comment(linker, "/EXPORT:VerQueryValueA=_AheadLib_VerQueryValueA,@14")
#pragma comment(linker, "/EXPORT:VerQueryValueW=_AheadLib_VerQueryValueW,@15")
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
宏定义
#define EXTERNC extern "C"
#define NAKED __declspec(naked)
#define EXPORT __declspec(dllexport)
#define ALCPP EXPORT NAKED
#define ALSTD EXTERNC EXPORT NAKED void __stdcall
#define ALCFAST EXTERNC EXPORT NAKED void __fastcall
#define ALCDECL EXTERNC NAKED void __cdecl
#define _UNICODE
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
BOOL
WINAPI DllMain(HMODULE , DWORD , PVOID );
BOOL
__stdcall ProtectMem(LPVOID, DWORD);
char strErr[
256
];
/
/
error info
FARPROC fpHookedAPI
=
0
;
/
/
addr of hooked api
FARPROC fpOrgHookedAPI
=
0
;
/
/
addr of safe place of hooked api, using it when
not
recoved
FARPROC fpNtPVM
=
0
;
/
/
addr of NtProtectVirtualMemory
FARPROC fpGCL
=
0
;
/
/
addr of hooked api
DWORD dwImageBaseXXXX
=
0
;
/
/
image base of target
DWORD dwRVAtoPatch
=
0xAABBCC
;
DWORD dwMyFileHandle;
/
/
file
handle to write
DWORD dwBytesWritten
=
0
;
WCHAR wcMyPath[
256
], wcMyFileName[
256
];
WCHAR wcSourcePath[
256
],
*
wcpSourcePath;
WCHAR wcDrive[
8
];
WCHAR wcDir[
256
];
WCHAR wcFileName[
64
];
WCHAR wcExt[
16
];
WCHAR
*
wcTmp1,
*
wcTmp2;
WCHAR wcSubStrBBBB[]
=
L
"CCCCDDDD"
;
/
/
WCHAR wcChar[]
=
"/"
;
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
main process to save XXX data
/
/
void NAKED MyAPI()
{
__asm{
nop
/
/
int
3
nop
nop
nop
pushad
nop
mov eax, [ebp
+
0x8
]
mov eax, [eax]
mov wcpSourcePath, eax
}
/
/
add patch code here
/
/
/
/
wcscpy(wcSourcePath, wcpSourcePath);
_wsplitpath(wcSourcePath, wcDrive, wcDir, wcFileName, wcExt);
wcTmp1
=
wcsstr(wcDir, wcSubStrBBBB);
/
/
find sub
str
of target
wcTmp2
=
wcschr(wcTmp1,
'/'
)
+
1
;
/
/
tmp2
=
"/username......./XXXXX/"
wcTmp1
=
wcschr(wcTmp2,
'/'
);
/
/
tmp2
=
"username......./XXXXX/"
wcscpy(wcMyPath, L
"D:/FFFFGGGG"
);
/
/
tmp1
=
/
xxxx
or
something
wcscat(wcMyPath, wcTmp1);
/
/
we got dst
dir
wcscpy(wcMyFileName, wcMyPath);
wcscat(wcMyFileName, wcFileName);
wcscat(wcMyFileName, wcExt);
/
/
we got dst filename
CreateDirectoryW(wcMyPath,
0
);
__asm{
nop
nop
push
0
push
0x80
push
2
push
0
push
0
push
0x40000000
lea ecx, wcMyFileName
push ecx
nop
mov eax, CreateFileW
call eax
/
/
create
file
nop
mov dwMyFileHandle, eax
inc eax
jz __fail_create_file
nop
nop
push
0
lea edx, dwBytesWritten
push edx
mov eax, [ebp
-
0xCC
]
/
/
plain length,
from
target
push eax
mov ecx, [ebp
-
0xDD
]
/
/
plain context
push ecx
mov eax, dwMyFileHandle
push eax
mov eax, WriteFile
/
/
write to
file
call eax
nop
nop
mov eax, dwMyFileHandle
push eax
mov eax, CloseHandle
call eax
/
/
close
file
nop
nop
__fail_create_file:
nop
}
/
/
__asm{
nop
nop
popad
nop
mov XXXXX, eax
/
/
restore code
cmp
eax, XXXXXX
nop
nop
ret
};
}
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
Hook 命名空间
namespace Hook
{
HHOOK m_hHook;
/
/
HOOK 句柄
/
/
HOOK 函数
LRESULT CALLBACK HookProc(
INT
iCode, WPARAM wParam, LPARAM lParam)
{
if
(iCode >
0
)
{
;
}
return
CallNextHookEx(m_hHook, iCode, wParam, lParam);
}
/
/
Hook
inline
BOOL
WINAPI Hook(
INT
iHookId
=
WH_CALLWNDPROC)
{
m_hHook
=
SetWindowsHookEx(iHookId, HookProc, NULL, GetCurrentThreadId());
return
(m_hHook !
=
NULL);
}
/
/
Unhook
inline VOID WINAPI Unhook()
{
if
(m_hHook)
{
UnhookWindowsHookEx(m_hHook);
}
}
}
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
AheadLib 命名空间
namespace AheadLib
{
HMODULE m_hModule
=
NULL;
/
/
原始模块句柄
DWORD m_dwReturn[
15
]
=
{
0
};
/
/
原始函数返回地址
/
/
加载原始模块
inline
BOOL
WINAPI Load()
{
TCHAR tzPath[MAX_PATH];
TCHAR tzTemp[MAX_PATH
*
2
];
GetSystemDirectory(tzPath, MAX_PATH);
lstrcat(tzPath, TEXT(
"\\version"
));
m_hModule
=
LoadLibrary(tzPath);
if
(m_hModule
=
=
NULL)
{
wsprintf(tzTemp, TEXT(
"无法加载 %s,程序无法正常运行。"
), tzPath);
MessageBox(NULL, tzTemp, TEXT(
"AheadLib"
), MB_ICONSTOP);
}
return
(m_hModule !
=
NULL);
}
/
/
释放原始模块
inline VOID WINAPI Free()
{
if
(m_hModule)
{
FreeLibrary(m_hModule);
}
}
/
/
获取原始函数地址
FARPROC WINAPI GetAddress(PCSTR pszProcName)
{
FARPROC fpAddress;
CHAR szProcName[
16
];
TCHAR tzTemp[MAX_PATH];
fpAddress
=
GetProcAddress(m_hModule, pszProcName);
if
(fpAddress
=
=
NULL)
{
if
(HIWORD(pszProcName)
=
=
0
)
{
wsprintf(szProcName,
"%d"
, pszProcName);
pszProcName
=
szProcName;
}
wsprintf(tzTemp, TEXT(
"无法找到函数 %hs,程序无法正常运行。"
), pszProcName);
MessageBox(NULL, tzTemp, TEXT(
"AheadLib"
), MB_ICONSTOP);
ExitProcess(
-
2
);
}
return
fpAddress;
}
}
using namespace AheadLib;
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
the code
is
copied
from
ntdll (win7)
/
/
dont know it will work
in
other OS
/
/
just
for
testing
/
/
BOOL
__declspec(naked) _NtProtectVirtualMemory()
{
__asm{
mov eax,
0x4d
xor ecx, ecx
lea edx, [esp
+
4
]
call fs:[
0xc0
]
add esp,
0x4
ret
0x14
}
}
/
/
set
page access to ReadWrite
/
/
call it first when writing mem fail
/
/
BOOL
__stdcall ProtectMem(LPVOID addr, DWORD dsize)
{
DWORD oldprotect;
DWORD nouse;
__asm{
lea eax, oldprotect
/
/
disgard
push eax
push PAGE_EXECUTE_READWRITE
/
/
lea eax, dsize
push eax
lea eax, addr
push eax
push
0xffffffff
/
/
call _NtProtectVirtualMemory
call [fpNtPVM]
test eax, eax
jz __pmGood
xor eax, eax
jmp __pmEnd
__pmGood:
xor eax, eax
inc eax
__pmEnd:
/
/
xor eax, eax
/
/
inc eax
/
/
ret
/
/
ret will be added by compiler
}
;
}
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
入口函数
/
/
这里不太需要改动了
BOOL
WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
HMODULE m_k32
=
NULL, m_nt
=
NULL;
/
/
handles
for
dll
__asm{
nop
nop
nop
/
/
int
3
nop
nop
}
if
(dwReason
=
=
DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
Hook::Hook();
strcpy(strErr, TEXT(
"API hooked."
));
/
/
m_k32
=
LoadLibrary(TEXT(
"kernel32"
));
/
/
getting GCL addr, this api will be hooked
if
(m_k32 !
=
NULL)
{
fpGCL
=
GetProcAddress(m_k32, TEXT(
"GetCommandLineW"
));
/
/
target uses W instead of A
fpHookedAPI
=
fpGCL;
}
else
{
strcpy(strErr, TEXT(
"k32 loaded fail"
));
__asm jmp __myDllInitEnd
}
m_nt
=
LoadLibrary(TEXT(
"ntdll"
));
/
/
getting ntPVM addr, this api will change page access, it
is
needed when patching mem.
if
(m_nt !
=
NULL)
fpNtPVM
=
GetProcAddress(m_nt, TEXT(
"NtProtectVirtualMemory"
));
else
{
strcpy(strErr, TEXT(
"nt loaded fail"
));
__asm jmp __myDllInitEnd
}
__asm{
/
/
find module of
'XXXX.dll'
/
/
luckyly, we found it, then we patch it.
/
/
nop
nop
pushad
nop
nop
mov ebx, hModule
mov edi, ebx
mov eax, fs:[
0x30
]
/
/
checking dll module (PEB)
mov eax, [eax
+
0xc
]
mov esi, [eax
+
0x14
]
mov edx, [eax
+
0x18
]
__chk_next_module:
lodsd
/
/
get LDR of current module
mov esi, eax
cmp
edx, esi
jz __not_found_module
mov ecx, [eax
+
0x28
]
/
/
get current module name
test ecx, ecx
jz __not_found_module
nop
/
/
cmp
module name,
is
my target?
push esi
mov esi, ecx
nop
nop
lodsd
cmp
eax,
0xAA00BB
/
/
"XX"
jz __chk_next_dword
pop esi
/
/
restore esi
mov eax, esi
jmp __chk_next_module
__chk_next_dword:
add esi,
0xc
/
/
we should chk it carefully
lodsd
cmp
eax,
0xCC00DD
/
/
check
next
2
bytes
jz __found_XX
nop
pop esi
mov eax, esi
jmp __chk_next_module
__found_XX:
nop
nop
pop esi
mov eax, esi
mov ecx, [eax
+
0x10
]
/
/
get imagebase of target
mov dwImageBaseXXXX, ecx
/
/
save imagebase
/
/
patch target
mov edi, dwImageBaseXXXX
add edi, dwRVAtoPatch
nop
nop
/
/
set
page
mov ecx,
0x7
push ecx
push edi
call ProtectMem
/
/
set
page access to ReadWrite
test eax, eax
je __myDllInitEnd
nop
nop
xor eax, eax
mov al,
0xe8
/
/
using
'call'
instead of
'jump'
causing we use
'ret'
to
return
, no need of thinking of jumping back
stosb
lea eax, MyAPI
/
/
set
jmp
's offset, patch code to '
myapi', our working process ;)
sub eax, edi
sub eax,
4
stosd
nop
mov ax,
0x9090
/
/
nop the
next
two bytes
stosw
nop
__not_found_module:
__myDllInitEnd:
nop
popad
/
/
return
};
/
/
/
/
::MessageBox(NULL, strErr,
"Info"
, MB_OK);
return
Load();
}
else
if
(dwReason
=
=
DLL_PROCESS_DETACH)
{
Free();
Hook::Unhook();
}
return
TRUE;
}
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
导出函数
ALCDECL AheadLib_GetFileVersionInfoA(void)
{
GetAddress(
"GetFileVersionInfoA"
);
__asm JMP EAX;
}
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
导出函数
/
/
....
/
/
nversion.cpp : Defines the entry point
for
the DLL application.
/
/
/
/
modified on the base of aheadlib
-
code
/
/
/
/
for
XXXXX ver XXXX, by Fpc
/
/
/
/
首先请原谅糟糕的代码水平 T_T
/
/
/
/
用途:
/
/
某软件解密的步骤是先读取文件,用复杂的算法得到中间结果,此中间结果生成后调用一个call完成解密和解压缩,本劫持用于保存生成的结果。
/
/
利用点:
/
/
在解密call完成后劫持代码,跳到我们的修改处,取得文件名信息,建立目标文件夹,建立目标文件,写文件,关文件,恢复现场,返回
/
/
修改难点:
/
/
原文件空间很有限,并且程序中的api数量有限,diy是利用起来不方便、找罪受
/
/
利用的优势:
/
/
劫持时机可以选择,对于代码量、api调用没限制,都是你自己可以编写的。
/
/
可利用的劫持时机:
/
/
比如采用version库,在被载入时通过peb
-
> ldr搜寻一下,此例中发现是幸运的,version加载后,目标dll已经加载完毕,可以对其patch了。注意要先使目标地址可写。
/
/
如果此时目标dll还没加载怎么办,需要多一个环节,先hook GetCommandLineA
/
W,主程序运行时一般dll都加载了,此时再去找目标dll,打补丁。(这是从一个补丁文件中学来的)
/
/
基本思路:
/
/
在内存中出现明文时并且提供了相关长度、文件路径等信息后,让代码跳到version我们自己编写的空间myapi中,取得这些信息,并生成保存新文件所需要的信息,建立文件夹(不需要判断是否成功),
/
/
建立文件,取得保存文件的信息,写文件,关闭文件,恢复现场,运行被破坏的指令,恢复到原代码处继续运行。
/
/
好处是在version空间内,写什么代码不受限制
/
/
#include "stdafx.h"
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
头文件
#include <Windows.h>
#include <stdio.h>
/
/
#include <psapi.h>
#include <tlhelp32.h>
#include <string>
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
导出函数
#pragma comment(linker, "/EXPORT:GetFileVersionInfoA=_AheadLib_GetFileVersionInfoA,@1")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoByHandle=_AheadLib_GetFileVersionInfoByHandle,@2")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExW=_AheadLib_GetFileVersionInfoExW,@3")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeA=_AheadLib_GetFileVersionInfoSizeA,@4")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExW=_AheadLib_GetFileVersionInfoSizeExW,@5")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeW=_AheadLib_GetFileVersionInfoSizeW,@6")
#pragma comment(linker, "/EXPORT:GetFileVersionInfoW=_AheadLib_GetFileVersionInfoW,@7")
#pragma comment(linker, "/EXPORT:VerFindFileA=_AheadLib_VerFindFileA,@8")
#pragma comment(linker, "/EXPORT:VerFindFileW=_AheadLib_VerFindFileW,@9")
#pragma comment(linker, "/EXPORT:VerInstallFileA=_AheadLib_VerInstallFileA,@10")
#pragma comment(linker, "/EXPORT:VerInstallFileW=_AheadLib_VerInstallFileW,@11")
#pragma comment(linker, "/EXPORT:VerLanguageNameA=_AheadLib_VerLanguageNameA,@12")
#pragma comment(linker, "/EXPORT:VerLanguageNameW=_AheadLib_VerLanguageNameW,@13")
#pragma comment(linker, "/EXPORT:VerQueryValueA=_AheadLib_VerQueryValueA,@14")
#pragma comment(linker, "/EXPORT:VerQueryValueW=_AheadLib_VerQueryValueW,@15")
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
宏定义
#define EXTERNC extern "C"
#define NAKED __declspec(naked)
#define EXPORT __declspec(dllexport)
#define ALCPP EXPORT NAKED
#define ALSTD EXTERNC EXPORT NAKED void __stdcall
#define ALCFAST EXTERNC EXPORT NAKED void __fastcall
#define ALCDECL EXTERNC NAKED void __cdecl
#define _UNICODE
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
BOOL
WINAPI DllMain(HMODULE , DWORD , PVOID );
BOOL
__stdcall ProtectMem(LPVOID, DWORD);
char strErr[
256
];
/
/
error info
FARPROC fpHookedAPI
=
0
;
/
/
addr of hooked api
FARPROC fpOrgHookedAPI
=
0
;
/
/
addr of safe place of hooked api, using it when
not
recoved
FARPROC fpNtPVM
=
0
;
/
/
addr of NtProtectVirtualMemory
FARPROC fpGCL
=
0
;
/
/
addr of hooked api
DWORD dwImageBaseXXXX
=
0
;
/
/
image base of target
DWORD dwRVAtoPatch
=
0xAABBCC
;
DWORD dwMyFileHandle;
/
/
file
handle to write
DWORD dwBytesWritten
=
0
;
WCHAR wcMyPath[
256
], wcMyFileName[
256
];
WCHAR wcSourcePath[
256
],
*
wcpSourcePath;
WCHAR wcDrive[
8
];
WCHAR wcDir[
256
];
WCHAR wcFileName[
64
];
WCHAR wcExt[
16
];
WCHAR
*
wcTmp1,
*
wcTmp2;
WCHAR wcSubStrBBBB[]
=
L
"CCCCDDDD"
;
/
/
WCHAR wcChar[]
=
"/"
;
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
main process to save XXX data
/
/
void NAKED MyAPI()
{
__asm{
nop
/
/
int
3
nop
nop
nop
pushad
nop
mov eax, [ebp
+
0x8
]
mov eax, [eax]
mov wcpSourcePath, eax
}
/
/
add patch code here
/
/
/
/
wcscpy(wcSourcePath, wcpSourcePath);
_wsplitpath(wcSourcePath, wcDrive, wcDir, wcFileName, wcExt);
wcTmp1
=
wcsstr(wcDir, wcSubStrBBBB);
/
/
find sub
str
of target
wcTmp2
=
wcschr(wcTmp1,
'/'
)
+
1
;
/
/
tmp2
=
"/username......./XXXXX/"
wcTmp1
=
wcschr(wcTmp2,
'/'
);
/
/
tmp2
=
"username......./XXXXX/"
wcscpy(wcMyPath, L
"D:/FFFFGGGG"
);
/
/
tmp1
=
/
xxxx
or
something
wcscat(wcMyPath, wcTmp1);
/
/
we got dst
dir
wcscpy(wcMyFileName, wcMyPath);
wcscat(wcMyFileName, wcFileName);
wcscat(wcMyFileName, wcExt);
/
/
we got dst filename
CreateDirectoryW(wcMyPath,
0
);
__asm{
nop
nop
push
0
push
0x80
push
2
push
0
push
0
push
0x40000000
lea ecx, wcMyFileName
push ecx
nop
mov eax, CreateFileW
call eax
/
/
create
file
nop
mov dwMyFileHandle, eax
inc eax
jz __fail_create_file
nop
nop
push
0
lea edx, dwBytesWritten
push edx
mov eax, [ebp
-
0xCC
]
/
/
plain length,
from
target
push eax
mov ecx, [ebp
-
0xDD
]
/
/
plain context
push ecx
mov eax, dwMyFileHandle
push eax
mov eax, WriteFile
/
/
write to
file
call eax
nop
nop
mov eax, dwMyFileHandle
push eax
mov eax, CloseHandle
call eax
/
/
close
file
nop
nop
__fail_create_file:
nop
}
/
/
__asm{
nop
nop
popad
nop
mov XXXXX, eax
/
/
restore code
cmp
eax, XXXXXX
nop
nop
ret
};
}
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
Hook 命名空间
namespace Hook
{
HHOOK m_hHook;
/
/
HOOK 句柄
/
/
HOOK 函数
LRESULT CALLBACK HookProc(
INT
iCode, WPARAM wParam, LPARAM lParam)
{
if
(iCode >
0
)
{
;
}
return
CallNextHookEx(m_hHook, iCode, wParam, lParam);
}
/
/
Hook
inline
BOOL
WINAPI Hook(
INT
iHookId
=
WH_CALLWNDPROC)
{
m_hHook
=
SetWindowsHookEx(iHookId, HookProc, NULL, GetCurrentThreadId());
return
(m_hHook !
=
NULL);
}
/
/
Unhook
inline VOID WINAPI Unhook()
{
if
(m_hHook)
{
UnhookWindowsHookEx(m_hHook);
}
}
}
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
/
AheadLib 命名空间
namespace AheadLib
{
HMODULE m_hModule
=
NULL;
/
/
原始模块句柄
DWORD m_dwReturn[
15
]
=
{
0
};
/
/
原始函数返回地址
/
/
加载原始模块
inline
BOOL
WINAPI Load()
{
TCHAR tzPath[MAX_PATH];
TCHAR tzTemp[MAX_PATH
*
2
];
GetSystemDirectory(tzPath, MAX_PATH);
lstrcat(tzPath, TEXT(
"\\version"
));
m_hModule
=
LoadLibrary(tzPath);
if
(m_hModule
=
=
NULL)
赞赏
他的文章
- [原创]一个hijack的实例 5052
- [原创]看雪秋季赛第2题出题思路 7052
- [原创]看雪2017 CTF 秋季赛第一题分析 3313
- [原创]CTF第七题简单思路,待补充 3483
看原图
赞赏
雪币:
留言: