Quote:
Originally Posted by xroute66x™ :)
Ich glaube , damit du es nur 1x schreiben musst, und es die für alle weiteren Quellcodes dieser Art wirkt.
|
Das ergibt nicht einmal grammatikalischen Sinn.
-----
Heute mal wieder ein kleiner Release zum Thema Hotpatching.
Große Teile der WinAPI sind mit dem Prefix "mov edi, edi" generiert. Das ist das gleiche wie zwei "nop" Anweisungen. Funktionen, die dieses Präfix haben, kann man sehr leicht hooken mit einer Hotpatch genannten Methode.
Mein Snippet setzt dabei folgendes voraus:
- Es wird kompiliert unter Visual Studio 2012,
- Das VC++ November 2012 CTP ist installiert (Download:
[Only registered and activated users can see links. Click Here To Register...]) und
- Das VC++ November 2012 CTP ist in Visual Studio aktiviert unter Projekteinstellungen (Alt+F7) > Konfigurationseigenschaften > Allgemein > Plattformtoolset.
Eine kleine Beispielanwendung, die die Anwendung für MessageBoxA/MessageBoxW zeigt, ist diese hier:
Code:
# include <iostream>
# include <Windows.h>
# include <cstdint>
# include <system_error>
class virtual_protect_lock
{
public:
virtual_protect_lock(void *ptr, const size_t size, const DWORD protection)
: ptr_(ptr), size_(size)
{
if (!::VirtualProtect(ptr_, size_, protection, &old_prot_))
throw std::system_error(::GetLastError(), std::system_category());
}
~virtual_protect_lock()
{
if (!::VirtualProtect(ptr_, size_, old_prot_, &old_prot_))
throw std::system_error(::GetLastError(), std::system_category());
}
private:
virtual_protect_lock(); // undefined
DWORD old_prot_;
void *ptr_;
const size_t size_;
};
template <typename _Return, typename... _Args>
auto install_hotpatch(_Return (__stdcall *target)(_Args...),
_Return (__stdcall *hook)(_Args...))
-> _Return (__stdcall *)(_Args...)
{
# pragma pack(push, 1)
struct signature_t
{
std::uint8_t long_jump;
std::uint32_t long_jump_adr;
std::uint16_t jump_back;
};
# pragma pack(pop)
struct signature_t *signature = reinterpret_cast<struct signature_t *>(
reinterpret_cast<uintptr_t>(target) - 5);
if ((signature->long_jump == 0x90) &&
(signature->long_jump_adr == 0x90909090) &&
(signature->jump_back == 0xFF8B))
try
{
virtual_protect_lock vplock(signature, sizeof(*signature),
PAGE_EXECUTE_WRITECOPY);
signature->long_jump = 0xE9;
signature->long_jump_adr = reinterpret_cast<uintptr_t>(hook)
- reinterpret_cast<uintptr_t>(target);
signature->jump_back = 0xF9EB;
}
catch(const std::system_error &)
{
throw;
}
return reinterpret_cast<_Return (__stdcall *)(_Args...)>(
reinterpret_cast<uintptr_t>(target) + 2);
}
template <typename _Return, typename... _Args>
void uninstall_hotpatch(_Return (__stdcall *target)(_Args...))
{
# pragma pack(push, 1)
struct signature_t
{
std::uint8_t long_jump;
std::uint32_t long_jump_adr;
std::uint16_t jump_back;
};
# pragma pack(pop)
struct signature_t *signature = reinterpret_cast<struct signature_t *>(
reinterpret_cast<uintptr_t>(target) - 5);
if ((signature->long_jump == 0xE9) &&
(signature->long_jump_adr != 0x90909090) &&
(signature->jump_back == 0xF9EB))
try
{
virtual_protect_lock vplock(signature, sizeof(*signature),
PAGE_EXECUTE_WRITECOPY);
signature->long_jump = 0x90;
signature->long_jump_adr = 0x90909090;
signature->jump_back = 0xFF8B;
}
catch(const std::system_error &)
{
throw;
}
}
decltype(MessageBox) *original_MessageBox;
int WINAPI hook_MessageBox(HWND hWnd, LPCTSTR lpText,
LPCTSTR lpCaption, UINT uType)
{
return original_MessageBox(hWnd, TEXT("replaced text"),
TEXT("replaced caption"), uType);
}
int main(int argc, char *argv[]) try
{
original_MessageBox = install_hotpatch(MessageBox, hook_MessageBox);
MessageBox(nullptr, TEXT("text"), TEXT("caption"), MB_OK);
uninstall_hotpatch(MessageBox);
MessageBox(nullptr, TEXT("text"), TEXT("caption"), MB_OK);
return 0;
}
catch(const std::system_error &err)
{
std::cout << err.what();
std::cin.get();
return err.code().value();
}
Eine kurze Erläuterung zu den einzelnen Sachen, die ich hier zusammengeschrieben habe:
(1) virtual_protect_lock verändert bei Objekterzeugung die Page-Protection, bei Verlassen des Scopes wird diese wieder zurückgesetzt. Tritt hierbei ein Fehler auf, wird ein std::system_error erzeugt und als exception geworfen. Der Errorcode ist das Ergebnis von GetLastError.
(2) install_hotpatch setzt den Hotpatch. Bei einem Fehler von virtual_protect_lock wird die Funktion abgebrochen, indem die Exception erneut geworfen wird. Die Funktion hat zwei Parameter: Einen Zeiger auf die Funktion, die man hooken möchte, und einen Zeiger auf den Hook selbst. Der Rückgabewert der Funktion ist ein Zeiger auf die originale Funktion nach dem Hook. Alle drei Funktionszeiger müssen exakt die gleiche Signatur haben. Wenn die Funktion für einen Hotpatch ungeeignet ist oder bereits einer installiert ist, passiert nichts.
(3) Die Funktion uninstall_hotpatch funktioniert analog zu install_hotpatch und entfernt den Hotpatch, wenn einer gesetzt ist. Einziges Parameter ist hier ein Zeiger auf die Funktion, deren Hotpatch man entfernen möchte.
Es sei dazu noch gesagt, dass man virtual_protect_lock nicht in STL Containern verwenden sollte, weil der Destruktor eine Exception werfen kann.
---
EDIT: Verwarnung, weil ich nach mehreren Tagen ohne aktiven Post einen Release in einen neuen Post packe anstatt sie in den alten zu packen? Was ist das denn bitte für eine Moderation?