View previous topic :: View next topic |
Author |
Message |
Baaleos
Joined: 02 Sep 2007 Posts: 830
|
Posted: Sun Aug 17, 2014 23:38 Post subject: NWNX Style Hooking in .Net |
|
|
Ok - I am currently working on my own wee project to use something called 'WhiteMagic' - a DLL that is commonly used for hooking and bot creation in games such as World of Warcraft - to facilitate .Net hooking and nwn api usage.
Example implementations:
Code: |
public static class Internals
{
public static AppManager AppMananger = new AppManager(); //0x0066c050;
private static uint NWN_VirtualMachine = 0x0066C048;
private static uint NWN_CTlkTable = 0x0066C054;
private static uint NWN_CNWTlkTable = 0x0066C058;
private static uint NWN_Rules = 0x0066c060;
private static uint NWN_ResMan = 0x0066C044;
//Note - not complete yet - only started doing AppManager so far
}
public class AppManager
{
public AppManager()
{
}
public static uint FinalAddress = setupAddress();
private static uint setupAddress()
{
if (FinalAddress == 0x0)
{
uint uPointVal = (uint)AccessMemory.ReadPointer(0x0066c050);
FinalAddress = uPointVal;
return uPointVal;
}
else
{
return FinalAddress;
}
}
public ServerExoApp ServerExoApp = new ServerExoApp();
}
public class ServerExoApp
{
static ServerExoApp()
{
//AppManager + 4 = ServerExoApp
FinalAddress = NWNDefinitions.AppManager.FinalAddress += 0x4;
FinalAddress = (uint)AccessMemory.ReadPointer(FinalAddress);
}
public static uint FinalAddress = 0x0;
#region Delegates
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
delegate int GetModuleLanguageDelegate(uint pThis);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
delegate uint GetGameObjectByIdDelegate(uint pThis, uint GameObjectID);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
delegate uint GetClientObjectByObjectIdDelgate(uint pThis, uint playerObjID);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
delegate uint GetNWSMessageDelegate(uint pThis);
#endregion
#region Method Setup
private static GetModuleLanguageDelegate Internal_GetModuleLanguage = WhiteMagic.Magic.Instance.RegisterDelegate<GetModuleLanguageDelegate>(0x0042C900);
private static GetGameObjectByIdDelegate Internal_GetGameObject = WhiteMagic.Magic.Instance.RegisterDelegate<GetGameObjectByIdDelegate>(0x0042C810);
private static GetClientObjectByObjectIdDelgate Internal_GetClientObjectByObjectID = WhiteMagic.Magic.Instance.RegisterDelegate<GetClientObjectByObjectIdDelgate>(0x0042cd20);
private static GetNWSMessageDelegate Internal_GetNWSMessage = WhiteMagic.Magic.Instance.RegisterDelegate<GetNWSMessageDelegate>(0x0042C940);
#endregion
//0x0042C900
/// <summary>
/// Returns server/module language
/// </summary>
/// <returns></returns>
public static int GetModuleLanguage()
{
return Internal_GetModuleLanguage(FinalAddress);
}
/// <summary>
/// Instantiates a new CNWSMessage object linked to the newly created message inside nwserver process
/// </summary>
/// <returns></returns>
public static Messaging.CNWSMessage GetNWNMessage()
{
Messaging.CNWSMessage msg = new Messaging.CNWSMessage((uint)Internal_GetNWSMessage(FinalAddress));
return msg;
}
/// <summary>
/// Gets the player object by NWNObjectID - Should probably provide GetGameObject output as the argument for this
/// </summary>
/// <param name="nwnObjID"></param>
/// <returns></returns>
public static uint GetClientObjectByObjectId(uint nwnObjID)
{
uint result = 0x0;
result = Internal_GetClientObjectByObjectID(FinalAddress, nwnObjID);
return result;
}
/// <summary>
/// Gets the NWNGameObject by its Object ID from in-game
/// </summary>
/// <param name="uInt"></param>
/// <returns></returns>
public static uint GetGameObject(string uInt)
{
uint NewValue = (uint)System.Int32.Parse(uInt, System.Globalization.NumberStyles.HexNumber);
uint retVal = Internal_GetGameObject(FinalAddress,NewValue);
return (uint)retVal;
}
}
|
The CExoApp example shows more of the implementation than the others.
Basically - I use the Internals class as a static class - to ensure that the pointers for it and its child classes get setup.
Eg:
Internals fires - which will fire AppManager - which gets its pointer, which then sets up the CExoApp with its pointer.
The delegates and the private method setup regions then link executable code to the internal nwn methods.
This project is a obviously less mature than the nwnx linux approach.
My current task I am working on is converting the nwnx_haks functionality over to a .net implementation.
To do so I have already hooked the PackModuleIntoMessage method in nwn
I just have to painfully work my way through it and re-create the nwnx_linux functionality - obviously my own .net project has lots of missing pieces - so I have to build them as I go.
Code: |
//Dont think we really need to do any work on the 'instance' as it will be the pThis for the CExoAppExternal : automatically provided?
private static void PackMessageHook(uint instance, uint uPlayer)
{
uint uclient = NWNDefinitions.ServerExoApp.GetClientObjectByObjectId(uPlayer);
NWNDotNet.NWNDefinitions.Messaging.CNWSMessage msg = NWNDefinitions.ServerExoApp.GetNWNMessage();
Magic.Instance.Detours["PackModuleIntoMessage"].CallOriginal(instance, uPlayer);
}
|
My problem however- is that I do not really fully understand what a CExoString is
For instance : in nwnx_haks
Code: |
uint32_t i;
CNWSPlayer *player = CServerExoApp__GetClientObjectByPlayerId((*NWN_AppManager)->app_server, pc, 0);
haks.Log(3, "object id: %d\n", player->obj_id);
haks.Log(3, "player id: %d\n", player->pl_id);
// MUST CALL SetPlayerEnhanced from what ever script is here!
nwn_ExecuteScript (enhance_script, player->obj_id);
CNWMessage *msg = (CNWMessage *)CServerExoApp__GetNWSMessage((*NWN_AppManager)->app_server);
CExoString ces;
// 68
char *cs = strchr(mod->mod_current_game.text, ':');
CExoString2 current_game(cs);
nwnx__WriteCExoString(msg, current_game, 0x20);
// 84 Server Name
CNWSMessage__WriteCExoLocStringServer((CNWSMessage *)msg, &(mod->mod_name), 0x20);
|
I can get as far as creating my CNWSMessage
But I dont know where in the nwnx_linux repo the definition for nwnx__WriteCExoString is located.
Can someone lend me a hand with understanding CExoStrings and maybe point me in the direction of some helpful libraries / source files to make me understand their use? |
|
Back to top |
|
|
leo_x
Joined: 25 Aug 2010 Posts: 75
|
Posted: Mon Aug 18, 2014 0:08 Post subject: Re: NWNX Style Hooking in .Net |
|
|
sorry, double post. _________________ the awakening (PW Action)
Last edited by leo_x on Mon Aug 18, 2014 0:11; edited 1 time in total |
|
Back to top |
|
|
leo_x
Joined: 25 Aug 2010 Posts: 75
|
Posted: Mon Aug 18, 2014 0:08 Post subject: Re: NWNX Style Hooking in .Net |
|
|
Baaleos wrote: | My problem however- is that I do not really fully understand what a CExoString is
For instance : in nwnx_haks
Code: |
uint32_t i;
CNWSPlayer *player = CServerExoApp__GetClientObjectByPlayerId((*NWN_AppManager)->app_server, pc, 0);
haks.Log(3, "object id: %d\n", player->obj_id);
haks.Log(3, "player id: %d\n", player->pl_id);
// MUST CALL SetPlayerEnhanced from what ever script is here!
nwn_ExecuteScript (enhance_script, player->obj_id);
CNWMessage *msg = (CNWMessage *)CServerExoApp__GetNWSMessage((*NWN_AppManager)->app_server);
CExoString ces;
// 68
char *cs = strchr(mod->mod_current_game.text, ':');
CExoString2 current_game(cs);
nwnx__WriteCExoString(msg, current_game, 0x20);
// 84 Server Name
CNWSMessage__WriteCExoLocStringServer((CNWSMessage *)msg, &(mod->mod_name), 0x20);
|
I can get as far as creating my CNWSMessage
But I dont know where in the nwnx_linux repo the definition for nwnx__WriteCExoString is located.
Can someone lend me a hand with understanding CExoStrings and maybe point me in the direction of some helpful libraries / source files to make me understand their use? |
Heya,
That code is rather out of date, this stuff might make things more plain: https://github.com/jd28/nwnx2-linux/blob/ta/plugins/haks/hooks/h_PackModuleIntoMessage.cpp that
nwnx__WriteCExoString is actually CNWMessage__WriteCExoString. In that original version I made some changes due to the fact that on linux some of the API's are C and some are C++.
CExoStrings are just a struct of a null terminated C string and an integer indicating length (which i don't think nwserver ever really uses). _________________ the awakening (PW Action) |
|
Back to top |
|
|
Baaleos
Joined: 02 Sep 2007 Posts: 830
|
Posted: Mon Aug 18, 2014 0:17 Post subject: |
|
|
Thanks Leo
That makes a bit more sense.
Do you happen to know how one implements a null terminated string in .Net?
I've never actually heard of that term before.
When looking at the Win32 api from nwnx_cool from Terra
I see the
Code: |
public:
char *text;
uint32_t len;
|
inside class CExoString_s {
and some of the constructors elsewhere:
Code: |
CExoString::CExoString() {
text = NULL;
len = 0;
}
CExoString::CExoString(CExoString const &Source) {
if (Source.text && strlen(Source.text) > 0) {
len = strlen(Source.text)+1;
text = new char[len];
strcpy_s(text, len, Source.text);
}
else {
text = NULL;
len = 0;
}
}
CExoString::CExoString(char const *Source) {
if (Source && strlen(Source) > 0) {
len = strlen(Source)+1;
text = new char[len];
strcpy_s(text, len, Source);
}
else {
text = NULL;
len = 0;
}
}
CExoString * CExoString::CExoStringCpy(char const *Source) {
if (Source && strlen(Source) > 0) {
len = strlen(Source)+1;
text = new char[len];
strcpy_s(text, len, Source);
}
else {
text = NULL;
len = 0;
}
return this;
}
CExoString::CExoString(char const *Source, int Length) {
if (Length > 0) {
len = Length+1;
text = new char[len];
strncpy_s(text, len, Source, Length);
}
else {
text = NULL;
len = 0;
}
}
CExoString::CExoString(int Number) {
char c[32];
sprintf_s(c, 31, "%i", Number);
len = strlen(c)+1;
text = new char[len];
strcpy_s(text, len, c);
}
CExoString::~CExoString() {
if (text) {
len = 0;
delete[] text;
text = NULL;
}
}
char *CExoString::CStr() {
return text;
}
|
I am just wondering if I could create a Class called CExoString and then have 2 fields for the text (as a char array) and the size of the char array as uint?
Would the size need to be textsize +1? |
|
Back to top |
|
|
leo_x
Joined: 25 Aug 2010 Posts: 75
|
Posted: Mon Aug 18, 2014 0:26 Post subject: |
|
|
I'm not sure on the C# part, I've not ever used it really. Since it's designed to work with windows API I can't imagine there isn't something for working with C strings.
The size of the string doesn't include the null character. That's how C++ std::string works and everything else I've seen works. _________________ the awakening (PW Action) |
|
Back to top |
|
|
Baaleos
Joined: 02 Sep 2007 Posts: 830
|
Posted: Mon Aug 18, 2014 0:57 Post subject: |
|
|
Im just wondering how to instantiate a CExoString - how do you guys instantiate one in Linux?
Do I need to setup the delegates as above - for the constructor methods?
I ask because I dont see that done in the linux code.
I couldnt find that method defined in any of the win32 nwnx code I have and IDA shows it as
Code: |
CNWSMessage::WriteCExoLocStringServer(class CExoLocString &, unsigned char)
|
Can you confirm - is there a constructor method that needs to be called to instantiate a CExoString?
So far in my .net implementation - I have been passing uint pointers as the objects.
Eg: If a method takes a creature, I supply the pointer (uint) that points to that creature.
I am just not sure how one gets that for a CExoString.
I suspect if I wanted to perform methods on it I would need to instantiate the class as a * pointer type, and then reference its pointer with the & operator.
Thats assuming I need to create my own class and set it up manually, opposed to using a nwserver constructor.
http://www.c-sharpcorner.com/UploadFile/rajeshvs/PointersInCSharp11112005051624AM/PointersInCSharp.aspx
I suppose I could always use generics?
Code: |
object* o = ConstructorForCExoString(string input);
//This might give me an object that I could then get the uint pointer for via
uint pointer = (uint)&o;
|
===
Edit
===
Scratch that
Code: |
char * CExoString::CStr() const
{
asm("leave");
asm("mov $0x082cc550, %eax");
asm("jmp *%eax");
}
|
I see this constructor in c++
I don't see an implementation for the overloaded versions - one accepts a string as input - I was rather hoping to use that one - for ease of use. |
|
Back to top |
|
|
nelak
Joined: 05 Oct 2012 Posts: 7
|
Posted: Fri Aug 22, 2014 6:49 Post subject: |
|
|
leo_x wrote: | I'm not sure on the C# part, I've not ever used it really. Since it's designed to work with windows API I can't imagine there isn't something for working with C strings.
The size of the string doesn't include the null character. That's how C++ std::string works and everything else I've seen works. |
Handling null terminated strings isn't too problematic in C#. By default, C# (and most other .NET language) strings are represented as a full data structure rather than just a pointer to a chunk of memory. The advantage is that C# strings are much safer than C strings since they always know their own length and they can also provide a number of extra features.
To convert to C strings, you would want to use the System.Text.Encoding.Unicode.GetBytes function and then just append "\0" to the end. (Edit: Now that I think about it, you'd probably want to use the ASCII.GetBytes rather than Unicode)
To convert from a C string to a C# string, you can using the System.Text.Encoding.ASCII.GetString function. It accepts a byte array - I don't believe it automatically removes the null terminator, but that is simple enough to fix. It takes arguments in asking how long the array is, just pass in 1 less than the length of the array and that will drop your null terminator.
You can also create your own extension methods, or a wrapper class that simplifies this, but that might be a little excessive since its just one line of code to go from C# string to C string and vice versa. |
|
Back to top |
|
|
Baaleos
Joined: 02 Sep 2007 Posts: 830
|
Posted: Sun Aug 24, 2014 20:41 Post subject: |
|
|
Without sounding like a complete noob.
Do I need to pass an actual CExoString to methods that require CExoStrings - or Can I actually pass a String to those methods?
Im not quite grasping how I should go about creating a CExoString and use that to pass the appropriate arguments to method such as CNWMessage__WriteCExoString |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|