logo logo

 Back to main page

The NWNX Community Forum

 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 
 
NWNX Style Hooking in .Net

 
Post new topic   Reply to topic    nwnx.org Forum Index -> Windows development
View previous topic :: View next topic  
Author Message
Baaleos



Joined: 02 Sep 2007
Posts: 830

PostPosted: Sun Aug 17, 2014 23:38    Post subject: NWNX Style Hooking in .Net Reply with quote

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
View user's profile Send private message
leo_x



Joined: 25 Aug 2010
Posts: 75

PostPosted: Mon Aug 18, 2014 0:08    Post subject: Re: NWNX Style Hooking in .Net Reply with quote

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
View user's profile Send private message
leo_x



Joined: 25 Aug 2010
Posts: 75

PostPosted: Mon Aug 18, 2014 0:08    Post subject: Re: NWNX Style Hooking in .Net Reply with quote

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
View user's profile Send private message
Baaleos



Joined: 02 Sep 2007
Posts: 830

PostPosted: Mon Aug 18, 2014 0:17    Post subject: Reply with quote

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
View user's profile Send private message
leo_x



Joined: 25 Aug 2010
Posts: 75

PostPosted: Mon Aug 18, 2014 0:26    Post subject: Reply with quote

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
View user's profile Send private message
Baaleos



Joined: 02 Sep 2007
Posts: 830

PostPosted: Mon Aug 18, 2014 0:57    Post subject: Reply with quote

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
View user's profile Send private message
nelak



Joined: 05 Oct 2012
Posts: 7

PostPosted: Fri Aug 22, 2014 6:49    Post subject: Reply with quote

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
View user's profile Send private message
Baaleos



Joined: 02 Sep 2007
Posts: 830

PostPosted: Sun Aug 24, 2014 20:41    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    nwnx.org Forum Index -> Windows development All times are GMT + 2 Hours
Page 1 of 1

 
Jump to:  
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