VTable Problem. Lösung gesucht.

10/09/2013 22:18 Crack-wtf#1
Ich habe ein "Problem" und brauche eine saubere Lösung.
Ich habe eine VTable eines Spiels und möchte nun:

1. Die VTable kopieren und das Spiel auf meine VTable zeigen lassen.
2. Bestimmte funktionen mit eigenen ersetzen.
3. In den veränderten funktionen die echte funktion callen können.

Wie regel ich das nun sauber?
Im moment mache ich es SEEHR unsauber so:

Char array in größe der VTable bereitstellen.
Memcpy auf mein Char array, mit der echten VTable.
Offsets manuell angeben und addresse mit der meiner funktion ersetzen.
Typedef der gewählten funktion erstellen, und die addresse der echten funktion nutzen um die echte zu callen.

Ich denke mal das Stichwort lautet "Wrapper", aber wie das funktioniert und ob das das ich was ich brauche weiß ich nicht.

Hoffe jemand hier hat eine gute idee.
10/09/2013 22:58 Dr. Coxxy#2
benutz die klasse hier oder lass dich davon inspirieren:
[Only registered and activated users can see links. Click Here To Register...]
10/09/2013 23:01 Crack-wtf#3
Edit: Ok leider für mein vorhaben nicht zu gebrauchen :(
1. Zuviel kram das ich nicht brauche. (Source zugemüllt und anfällig für Patternscans.)
2. Keine Möglichkeit gegeben die echte funktion zu callen.
10/10/2013 01:06 Tasiro#4
Es gibt das Problem, dass Compiler versuchen, den tatsächlichen Typ eines Objekts zu ermitteln so den Umweg über die Tabelle virtueller Methoden zu vermeiden.

Prinzipiell lässt sich eine Methode über Methodenzeiger standardkonform so aufrufen:
Code:
#include <iostream>
#include <functional>

int main () {
	typedef std::multiplies <int> class_type;
	class_type m;
	typedef decltype (class_type::operator ()) method_type;
	auto method (& class_type::operator ());		// Kopierkonstruktor
	auto this_ptr (& m);
	int i = std::mem_fn (method) (this_ptr, 2, 3);
	std::cout << i << '\n';
	std::cin.get ();
}
Jetzt musst du noch die entsprechende Klasse mit virtuellen Methoden soweit nachstellen, damit der Compiler dir die Arbeit mit der Tabelle virtueller Funktionen abnimmt, und eine Zahl in einen Methodenzeiger konvertieren. Für letzteres bieten sich Suchmaschine und reinterpret_cast<method_type*> an.
Der letzte Schritt wäre dann, die Orginaltabelle umzuschreiben.

Da böte sich eine passende TMP-Bibliothek wirklich an, vielleicht mit Wrapper-Klasse?
10/10/2013 01:11 Dr. Coxxy#5
Quote:
Originally Posted by Crack-wtf View Post
Edit: Ok leider für mein vorhaben nicht zu gebrauchen :(
1. Zuviel kram das ich nicht brauche. (Source zugemüllt und anfällig für Patternscans.)
2. Keine Möglichkeit gegeben die echte funktion zu callen.
1. Deswegen sagte ich, du kannst dich davon inspirieren lassen und es selber nachbauen, hab ich auch, bzw. schon bevor ichs kannte.
2. doch, soweit ich weiß schon, zwar noch nie benutzt das teil, aber in dem thread steht:
Quote:
template< typename Fn > Fn VMTManager::GetMethod( size_t index ) const;
Get the original function. I highly suggest this over unhooking.
Use a function prototype for the template argument to make it very easy to call this function. Example syntax: hook.GetMethod<bool (__thiscall*)( void*, int )>( 12 )( inst, arg );
10/10/2013 03:25 Raz9r#6
Ich benutze dafür immer std::tuple. Da das allerdings meistens so implementiert ist, dass im Speicher die Objekte in umgekehrter Reihenfolge stehen, muss man die Reihenfolge meistens umkehren (in VS2013 RC ist das so). Dann kann man mit memcpy in das reverse_tuple (s. unten) kopieren.

Code:
namespace detail {
	template <typename, typename>
	struct append_to_type_seq { };

	template <typename T, typename... Ts>
	struct append_to_type_seq<T, std::tuple<Ts...>> {
		using type = std::tuple<Ts..., T>;
	};

	template <typename... Ts>
	struct revert_type_seq {
		using type = std::tuple<>;
	};

	template <typename T, typename... Ts>
	struct revert_type_seq<T, Ts...> {
		using type = typename append_to_type_seq<T, typename revert_type_seq<Ts...>::type>::type;
	};


}

template <typename... Ts>
using reverse_tuple = typename detail::revert_type_seq<Ts...>::type;
Beispielsanwendung:
Code:
// VMT für my_class
using my_class_vmt = reverse_tuple<
/*00*/ void (__stdcall *)(void *),
/*01*/ int (__thiscall *)(my_class *, double)
>;

// vtable kopieren (geht natürlich auch in die andere Richtung)
my_class_vmt vmt;
memcpy(&vmt, vptr, sizeof(vmt));

// einzelnen eintrag modifizieren:
auto pvmt = reinterpret_cast<my_class_vmt *>(vptr);
std::get<Index>(*pvmt) = some_other_function_pointer;
Ist IMHO eine flexible Lösung des Problems.
10/10/2013 03:53 Crack-wtf#7
Quote:
Originally Posted by Raz9r View Post
Ich benutze dafür immer std::tuple. Da das allerdings meistens so implementiert ist, dass im Speicher die Objekte in umgekehrter Reihenfolge stehen, muss man die Reihenfolge meistens umkehren (in VS2013 RC ist das so). Dann kann man mit memcpy in das reverse_tuple (s. unten) kopieren.

Code:
namespace detail {
	template <typename, typename>
	struct append_to_type_seq { };

	template <typename T, typename... Ts>
	struct append_to_type_seq<T, std::tuple<Ts...>> {
		using type = std::tuple<Ts..., T>;
	};

	template <typename... Ts>
	struct revert_type_seq {
		using type = std::tuple<>;
	};

	template <typename T, typename... Ts>
	struct revert_type_seq<T, Ts...> {
		using type = typename append_to_type_seq<T, typename revert_type_seq<Ts...>::type>::type;
	};


}

template <typename... Ts>
using reverse_tuple = typename detail::revert_type_seq<Ts...>::type;
Beispielsanwendung:
Code:
// VMT für my_class
using my_class_vmt = reverse_tuple<
/*00*/ void (__stdcall *)(void *),
/*01*/ int (__thiscall *)(my_class *, double)
>;

// vtable kopieren (geht natürlich auch in die andere Richtung)
my_class_vmt vmt;
memcpy(&vmt, vptr, sizeof(vmt));

// einzelnen eintrag modifizieren:
auto pvmt = reinterpret_cast<my_class_vmt *>(vptr);
std::get<Index>(*pvmt) = some_other_function_pointer;
Ist IMHO eine flexible Lösung des Problems.
Ok das muss ich mir noch paarmal ansehen.