гений, плейбой, но не миллиардер
-
Автор темы
- #1
Изначально эта статья писалась для форума эвольва. Но ее автор я, приступим.
Что нам нужно:
IDA Pro с SigMaker плагином
Visual Studio или CLion
x32dbg для дебага
DirectX SDK.
Первое:
Инклудим минхуки, и дхсдк. Пример для cmake:
Теперь создаем наш поток с читом:
код потока:
Теперь нам нужна функция findPattern, я взял ее с csgosimple
И функция get_virtual:
Теперь нам нужно найти паттерн. Открываем shaderapidx9.dll в иде и
Если мы немного посмотрим в слитый исходный код, то увидим, что девайс называется D3DDevice и функции с использованием D3DDevice выкидывают ошибки.
Я к примеру возьму CIndexBufferDx8::Allocate: CreateIndexBuffer failed!\n.
Ищем эту строку в иде.
Референс из исходного кода движка:
По моему мнению
это является вызовом виртуальной функции, с индексом 26.
Проверяем и видим, что CreateIndexBuffer имеет индекс 26, следовательно мы верно трактовали этот код, и dword_1018698C является нашим девайсом. Делаем паттерн, я считаю A1 ? ? ? ? 8D 53 08 красивым паттерном, поэтому возьму его.
Теперь нам надо просканировать паттерн.
Инициализируем минхук:
Создаем прототип эндсцены:
Хукаем:
В нашем хуке возвращаем оригинал в самом конце.
Я не являюсь профессионалом в этой области, да и я свою же статью криво перевел, но надеюсь она вам понравится. Хев фан
Что нам нужно:
IDA Pro с SigMaker плагином
Visual Studio или CLion
x32dbg для дебага
DirectX SDK.
Первое:
Инклудим минхуки, и дхсдк. Пример для cmake:
Код:
include_directories(
"C:\\Users\\chrshnv\\Desktop\\dxsdk\\Include"
"C:\\Users\\chrshnv\\Desktop\\minhook-master\\include"
)
link_directories(
"C:\\Users\\chrshnv\\Desktop\\dxsdk\\Lib\\x86"
"C:\\Users\\chrshnv\\Desktop\\minhook-master\\build\\VC16\\lib"
)
Код:
if ( dwReason == DLL_PROCESS_ATTACH )
{
CreateThread( nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(main_thread), 0, 0, 0 );
}
Код:
DWORD WINAPI main_thread( )
{
hooks::init( );
while( true )
{
}
return TRUE;
}
Теперь нам нужна функция findPattern, я взял ее с csgosimple
C++:
std::uint8_t* helpers::pattern_scan(void* module, const char* signature)
{
static auto pattern_to_byte = [](const char* pattern) {
auto bytes = std::vector<int>{};
auto start = const_cast<char*>(pattern);
auto end = const_cast<char*>(pattern) + strlen(pattern);
for(auto current = start; current < end; ++current) {
if(*current == '?') {
++current;
if(*current == '?')
++current;
bytes.push_back(-1);
} else {
bytes.push_back(strtoul(current, ¤t, 16));
}
}
return bytes;
};
auto dosHeader = (PIMAGE_DOS_HEADER)module;
auto ntHeaders = (PIMAGE_NT_HEADERS)((std::uint8_t*)module + dosHeader->e_lfanew);
auto sizeOfImage = ntHeaders->OptionalHeader.SizeOfImage;
auto patternBytes = pattern_to_byte(signature);
auto scanBytes = reinterpret_cast<std::uint8_t*>(module);
auto s = patternBytes.size();
auto d = patternBytes.data();
for(auto i = 0ul; i < sizeOfImage - s; ++i) {
bool found = true;
for(auto j = 0ul; j < s; ++j) {
if(scanBytes[i + j] != d[j] && d[j] != -1) {
found = false;
break;
}
}
if(found) {
return &scanBytes[i];
}
}
return nullptr;
}
И функция get_virtual:
C++:
unsigned int helpers::get_virtual(void* _class, unsigned int index)
{
return static_cast<unsigned int>((*reinterpret_cast<int**>(_class))[index]);
}
Теперь нам нужно найти паттерн. Открываем shaderapidx9.dll в иде и
Пожалуйста, авторизуйтесь для просмотра ссылки.
Если мы немного посмотрим в слитый исходный код, то увидим, что девайс называется D3DDevice и функции с использованием D3DDevice выкидывают ошибки.
Я к примеру возьму CIndexBufferDx8::Allocate: CreateIndexBuffer failed!\n.
Ищем эту строку в иде.
C++:
v4 = (*(int (__stdcall **)(int, _DWORD, int, _DWORD, int, _DWORD *, _DWORD))(*(_DWORD *)dword_1018698C + 104))(
dword_1018698C,
this[7],
v3,
0,
v2,
this + 2,
0);
if ( v4 == -2005532292 || v4 == -2147024882 )
{
(*(void (__stdcall **)(int))(*(_DWORD *)dword_1018698C + 20))(dword_1018698C);
v4 = (*(int (__stdcall **)(int, _DWORD, int, _DWORD, int, _DWORD *, _DWORD))(*(_DWORD *)dword_1018698C + 104))(
dword_1018698C,
this[7],
v3,
0,
v2,
this + 2,
0);
}
if ( v4 >= 0 && this[2] )
{
v5 = sub_100B4F10(this[4], this[5]);
v6 = *(void (__thiscall ***)(int, _DWORD, bool, _DWORD, int, _DWORD, _DWORD))dword_1019EF24;
v7 = ((__int64 (__thiscall *)(_DWORD *))*(_DWORD *)(*this + 8))(this);
(*v6)(dword_1019EF24, this[2], (this[9] & 2) != 0, this[7], v5, v7, HIDWORD(v7));
if ( (this[9] & 2) == 0 )
*(_DWORD *)this[12] += this[7];
result = 1;
}
else
{
Warning("CVertexBufferDx8::Allocate: CreateVertexBuffer failed!\n");
result = 0;
}
Референс из исходного кода движка:
C++:
HRESULT hr = Dx9Device()->CreateIndexBuffer(
m_nBufferSize, usage, format, D3DPOOL_DEFAULT, &m_pIndexBuffer, NULL );
#if !defined( _X360 )
if ( ( hr == D3DERR_OUTOFVIDEOMEMORY ) || ( hr == E_OUTOFMEMORY ) )
{
// Don't have the memory for this. Try flushing all managed resources
// out of vid mem and try again.
// FIXME: need to record this
Dx9Device()->EvictManagedResources();
hr = Dx9Device()->CreateIndexBuffer(
m_nBufferSize, usage, format, D3DPOOL_DEFAULT, &m_pIndexBuffer, NULL );
}
#endif // !X360
if ( FAILED(hr) || ( m_pIndexBuffer == NULL ) )
{
Warning( "CIndexBufferDx8::Allocate: CreateIndexBuffer failed!\n" );
return false;
}
По моему мнению
C++:
v4 = (*(int (__stdcall **)(int, _DWORD, int, _DWORD, int, _DWORD *, _DWORD))(*(_DWORD *)dword_1018698C + 104))(
dword_1018698C,
this[7],
v3,
0,
v2,
this + 2,
0);
}
Проверяем и видим, что CreateIndexBuffer имеет индекс 26, следовательно мы верно трактовали этот код, и dword_1018698C является нашим девайсом. Делаем паттерн, я считаю A1 ? ? ? ? 8D 53 08 красивым паттерном, поэтому возьму его.
Теперь нам надо просканировать паттерн.
Код:
IDirect3DDevice9* device = **( IDirect3DDevice9*** )( helpers::pattern_scan( GetModuleHandle( "shaderapidx9.dll" ), "A1 ? ? ? ? 8D 53 08" ) + 1 );
Инициализируем минхук:
C++:
if( MH_Initialize( ) != MH_OK )
throw std::runtime_error( "failed to initialize minhook" );
Создаем прототип эндсцены:
C++:
long __stdcall hooked_endscene( IDirect3DDevice9* device );
typedef long( __stdcall* endscene_function )( IDirect3DDevice9* );
extern endscene_function original_endscene;
Хукаем:
C++:
if( MH_CreateHook( target, reinterpret_cast<void*>( &hooked_endscene ), reinterpret_cast<void**>( &original_endscene ) ) != MH_OK )
throw std::runtime_error( "failed to create endscene" );
if( MH_EnableHook( MH_ALL_HOOKS ) != MH_OK )
throw std::runtime_error( "failed to enable hooks" );
В нашем хуке возвращаем оригинал в самом конце.
Я не являюсь профессионалом в этой области, да и я свою же статью криво перевел, но надеюсь она вам понравится. Хев фан