View previous topic :: View next topic |
Author |
Message |
PlasmaJohn
Joined: 04 Mar 2005 Posts: 70 Location: The Garage
|
Posted: Sat Jan 07, 2006 21:29 Post subject: |
|
|
PlasmaJohn wrote: | BTW, this should be usable via the following code:
Code: | int (*pExecuteScript)(char**,int,int) = 0x05af2c0;
int MyFunc( /* other args */, int obj ) {
...
(*pExecuteScript)("ext_event",obj,1);
...
} |
|
Ok, no joy with this method. I'm no expert on Windoze, so can somebody clue me in how to make this call at this address please?
isilweo wrote: | Some technical part.
ExecuteScript is located on 0x05AF2C0. It takes three parameters on stack and one passed using ecx. Parameters are ExecuteScript(char ** ScriptName, int ObjectId, int Something = 1). Something is always 1 when running script, maybe that function is used for something else when something!=1 - i don't know. In EAX there's pointer to static variable which probably contains ScriptResult (or something like that). Can't tell you address right now cause i'm not at my computer. |
|
|
Back to top |
|
|
PlasmaJohn
Joined: 04 Mar 2005 Posts: 70 Location: The Garage
|
Posted: Fri Jan 13, 2006 18:17 Post subject: |
|
|
*poke-poke-poke-pokety-pokety-poke*
Help?
This is the event injector that I've been looking for for over a year. There are several really cool things it can be used for. For instance: real-time cross-server communication. External AI. Ability to offload complicated computation to an external process or thread.
Anything that you currently poll (Autobic, Vaultster, etc.) can now run a script that lets the engine know that it's done or has encountered an error. |
|
Back to top |
|
|
Zebranky
Joined: 04 Jun 2006 Posts: 415
|
Posted: Fri Jul 21, 2006 5:44 Post subject: |
|
|
After several attempts, I have re-implemented this POC. The following code, included in any NWNx plugin, will execute the script in scriptname. OBJECT_SELF will be the module (the second arg in the pExecScript call).
For the technical: the 1.67 address of the ExecuteScript() function is 0x005baba0. It still takes three arguments as described by isilweo. The argument on ECX is the C++ 'this' pointer. It varies based on NWNx modules loaded, but is always stored in 0x00661b38. This code simply loads that pointer into ECX, then calls the function with the provided args. Many thanks to isilweo for the idea, and PlasmaJohn for part of the implementation, especially realizing that ECX is the 'this' pointer.
Code: | char *scriptname = "arbitrary";
typedef int (__stdcall *ExecFP)(char **, int,int);
ExecFP pExecScript = (int(__stdcall*)(char**,int,int))0x005baba0;
void CNWNXPlugin::Exec() {
__asm { push esp
mov ecx, dword ptr ds:[0x00661b38]
}
(*pExecScript)(&scriptname,0,1);
__asm { pop esp }
} |
|
|
Back to top |
|
|
PlasmaJohn
Joined: 04 Mar 2005 Posts: 70 Location: The Garage
|
Posted: Fri Jul 21, 2006 14:22 Post subject: |
|
|
Ooh, thanks for the 167 addresses.
I know I made a post awhile ago about this, must have gotten lost in the crash. Getting this to work is a big first step, however there's another thing that needs to be dealt with. The script engine can only run in one thread at a time, so something needs to manage the locking. Probably the best place for that would be ResMan as that inserts itself into between script call and script execution. |
|
Back to top |
|
|
virusman
Joined: 30 Jan 2005 Posts: 1020 Location: Russia
|
Posted: Fri Jul 21, 2006 17:38 Post subject: |
|
|
PlasmaJohn wrote: | Ooh, thanks for the 167 addresses.
I know I made a post awhile ago about this, must have gotten lost in the crash. Getting this to work is a big first step, however there's another thing that needs to be dealt with. The script engine can only run in one thread at a time, so something needs to manage the locking. Probably the best place for that would be ResMan as that inserts itself into between script call and script execution. | No, Resman hooks the LoadResource function (or something like that).
RunScript calls LoadScript (-> LoadResource) and then ExecuteScript. ExecuteScript is hooked by Profiler.
But it doesn't matter in this case. Just calling RunScript works ok.
Btw, what are you trying to do? If you want to run nwscripts from nwnx-plugin, just look at the Chat plugin sources.
Code: | // 53 55 56 57 8B 7C 24 14 8B F1 8B CF
DWORD FindRunScript()
{
char* ptr = (char*) 0x400000;
while (ptr < (char*) 0x600000)
{
if ((ptr[0] == (char) 0x53) &&
(ptr[1] == (char) 0x55) &&
(ptr[2] == (char) 0x56) &&
(ptr[3] == (char) 0x57) &&
(ptr[4] == (char) 0x8B) &&
(ptr[5] == (char) 0x7C) &&
(ptr[6] == (char) 0x24) &&
(ptr[7] == (char) 0x14) &&
(ptr[8] == (char) 0x8B) &&
(ptr[9] == (char) 0xF1) &&
(ptr[10] == (char) 0x8B) &&
(ptr[11] == (char) 0xCF)
)
return (DWORD) ptr;
else
ptr++;
}
return NULL;
}
void RunScript(char * sname, int ObjID)
{
int sptr[4];
sptr[1] = strlen(sname);
_asm {
lea edx, sptr
mov eax, sname
mov [edx], eax
push 1
push ObjID
push edx
mov ecx, pScriptThis
mov ecx, [ecx]
}
scriptRun = 1;
pRunScript();
scriptRun = 0;
}
int HookFunctions()
{
DWORD org_Run = FindRunScript();
}
| (c) dumbo |
|
Back to top |
|
|
PlasmaJohn
Joined: 04 Mar 2005 Posts: 70 Location: The Garage
|
Posted: Fri Jul 21, 2006 21:37 Post subject: |
|
|
virusman wrote: | Btw, what are you trying to do? If you want to run nwscripts from nwnx-plugin, just look at the Chat plugin sources. |
What we're trying to do is to run scripts in response to external stimuli, like a web page, or an IM application without requiring the VM to poll. I'd be just as happy with plugin code that'll add an event to the event queue.
The nwnx_inject plugin starts a new thread and listens for external events on a configurable UDP port. Using the addresses that Zebranky found, we can call the RunScript(?) function from that thread and not have to wait for the script VM to get around to polling for new events. The problem is that if the inject thread tries to enter RunScript while the thread that the script VM is running in is doing the same, bad thing happen. So we need to synchronize between them.
Anything that hooks RunScript, is a good place to manage that mutex. I think. |
|
Back to top |
|
|
virusman
Joined: 30 Jan 2005 Posts: 1020 Location: Russia
|
Posted: Fri Jul 21, 2006 21:51 Post subject: |
|
|
PlasmaJohn wrote: | The problem is that if the inject thread tries to enter RunScript while the thread that the script VM is running in is doing the same, bad thing happen. So we need to synchronize between them.
Anything that hooks RunScript, is a good place to manage that mutex. I think. | Have you tried it or it's just an assumption? |
|
Back to top |
|
|
PlasmaJohn
Joined: 04 Mar 2005 Posts: 70 Location: The Garage
|
Posted: Fri Jul 21, 2006 22:26 Post subject: |
|
|
virusman wrote: | Have you tried it or it's just an assumption? |
Tried what? Crashing the server? Yes, quite spectacularly as expected. If it were stable I'd be using it.
Hooking nwnx_chat? No, first time I've seriously considered it and I haven't touched NWNX code in months. |
|
Back to top |
|
|
chaoslink
Joined: 23 Aug 2006 Posts: 37
|
Posted: Thu Aug 24, 2006 0:01 Post subject: |
|
|
Why not hook into RunScript like how ResMan hooks DemandRes?
You could make that hook code the synchronization point for both script execution mechanisms.
[edit: oops, I realize that's what the above post was saying, sorry] |
|
Back to top |
|
|
Zebranky
Joined: 04 Jun 2006 Posts: 415
|
Posted: Thu Aug 24, 2006 4:14 Post subject: |
|
|
I might have gotten this mutex working... I just need to be able to test it. Implementing a mutex on hooked nwserver code is cake compared to dealing with MFC and the Windows API... |
|
Back to top |
|
|
chaoslink
Joined: 23 Aug 2006 Posts: 37
|
Posted: Thu Aug 24, 2006 9:04 Post subject: |
|
|
Gah, you're telling me! Why your bothering with that junk is beyond me
I may write my own version of this that compiles for both windows and linux (there seems to be a general lack of portable code around here). |
|
Back to top |
|
|
Zebranky
Joined: 04 Jun 2006 Posts: 415
|
Posted: Fri Aug 25, 2006 4:32 Post subject: |
|
|
Hey, it's still a POC. I can write nasty non-portable code if I want to.
I actually can't reproduce that crash, though... |
|
Back to top |
|
|
Zebranky
Joined: 04 Jun 2006 Posts: 415
|
Posted: Mon Aug 28, 2006 6:08 Post subject: |
|
|
This is in live testing in an isolated area on Hades. An NPC is speaking a one-liner every tenth of a second without problems. |
|
Back to top |
|
|
chaoslink
Joined: 23 Aug 2006 Posts: 37
|
Posted: Tue Aug 29, 2006 0:56 Post subject: |
|
|
Zebranky wrote: | Hey, it's still a POC. I can write nasty non-portable code if I want to.
I actually can't reproduce that crash, though... |
Muahahaha! |
|
Back to top |
|
|
Zebranky
Joined: 04 Jun 2006 Posts: 415
|
Posted: Tue Aug 29, 2006 4:14 Post subject: |
|
|
Curses. After 24 hours, 16 minutes, and 43 seconds, it failed miserably. Back to the drawing board (or IDE, as the case may be). |
|
Back to top |
|
|
|