PWI - Guide for finding chat message offsets - C# code included

03/19/2012 19:22 dumbfck#121
[Only registered and activated users can see links. Click Here To Register...]
04/02/2012 14:26 amineurin#122
i start payling with this:
Quote:
uint dwItemId // 0x0C ID of an item linked in chat
but the numer 9742236 i get, is no item in pw database.
is this number only for a item list inside pwi or did i miss something on the description ?
since reading chat text works fine, i use the same way be useing C then 8.
04/02/2012 14:36 dumbfck#123
Yeah I had originally incorrectly marked that offset as itemID, when in fact it is actually a pointer to the item object / struct. I have figured that stuff out but it's not for the feint hearted lol. Also, it will be one of the features I intend to utilise in my upcoming program I shall be releasing in the future, so I don't want to give too much away just yet :p
I'll send you some info via PM later though as I trust you won't publish it ;)
04/02/2012 14:51 amineurin#124
ah thanks dumbfck, i just wonder myself here about the number and the pw database number :D
and u cooking again on something, i can swear i smell something wonderfull ;)
04/10/2012 06:26 Shopko#125
You guys are amazing. Thanks so much for this thread! As far as actually chatting, I know it's a lame way to do it but you can send keystroke messages to the elementclient window directly. I'm playing around with sending WM_KEYDOWN and WM_KEYUP to the window now. I just need to figure out how to put keyboard focus on the chat area. I'll post again if I get it working.

Quote:
Originally Posted by Shopko View Post
You guys are amazing. Thanks so much for this thread! As far as actually chatting, I know it's a lame way to do it but you can send keystroke messages to the elementclient window directly. I'm playing around with sending WM_KEYDOWN and WM_KEYUP to the window now. I just need to figure out how to put keyboard focus on the chat area. I'll post again if I get it working.
Well, damn that was surprising. Ctrl + D clears the chat window but also has the side effect of putting focus on the chat entry area. So, since the program on the first page already has a copy of the chat log in memory, we don't care if it gets cleared in elementclient.

My hope is to leave elementclient minimized and yet be able to send chat messages. If I get that working then I'll post the total project. :)
04/10/2012 10:44 amineurin#126
Quote:
Originally Posted by Shopko View Post
My hope is to leave elementclient minimized and yet be able to send chat messages. If I get that working then I'll post the total project. :)
take a look on this autoit function:
Quote:
Global $APP_BASE_ADDRESSFZ=10825500


;repeat this call every second or so...
unFreeze()


; the function...
Func unFreeze()
$FZ = _MemoryRead($APP_BASE_ADDRESSFZ, $PROCESS_INFORMATION)
If $FZ <> 1 Then
_MemoryWrite($APP_BASE_ADDRESSFZ, $PROCESS_INFORMATION, "1")
EndIf
EndFunc
now your window can be minimized :)
04/10/2012 19:06 Shopko#127
That's pretty cool. :) I always [Only registered and activated users can see links. Click Here To Register...] anyway, but the unfreeze bit is a neat trick. Thanks!

I think I ran into a show-stopper with the Windows messages though. :mad: Windows keyboard input is stupid. First, your bot either has to run as Administrator or you have to turn User Account Control (UAC) off to be able to send messages to arbitrary windows, like elementclient. Second, when you press a key on the keyboard the following messages are sent to whatever program is in the foreground:

WM_KEYDOWN
WM_CHAR
WM_KEYUP

When the program gets the WM_CHAR message, it looks up the current "shift state" of the keyboard to figure out whether or not any of the Control, Alt, or Shift keys are down. There's no way to force that shift state just by sending messages. The result is that everything that gets typed in to elementclient is all uppercase, which is really annoying.

There is another Win32 call named "SendInput". This call *does* force the shift state, but it doesn't send keystrokes to any application you tell it to; instead, it sends keystrokes to whatever program is currently in the foreground. The equivalent wrapper call in .NET is System.Windows.Forms.SendKeys.

So, my hack solution goes something like this (the code below is C#):

Code:
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);

public void LocalChatMessage(string message)
{
    // Give elementclient focus
    SetForegroundWindow(m_hWnd);

    // Send the Control-D key sequence to give the chat area focus
    SendKeys.SendWait("^d");

    // Press backspace a bunch of times to get rid of any whisper names
    // or PWI chat identifiers (!@, !~, !!, etc.)
    SendKeys.SendWait("{BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}{BS}");

    // Type the message in local chat
    SendKeys.SendWait(message + "\n");
}
It just really sucks that the elementclient has to be in the foreground to send simulated keystrokes to it. Ideally, we will eventually be able to figure out the parameters for the chat calls built in to elementclient...
04/10/2012 22:36 amineurin#128
hehe this reminds me at my first bot, a mats farmer.
were i use the wasd keys to move the bot :D

maybe take a look at the prophet bot source, he send keys to the minimized client window and a lot more.
im sure if u take a look inside and check some ways to work, u get it all.

after u use the unfreeze, take a look at this:
send a key, to a minimized window too without nerving other open programms goes like this:
Quote:
_SendMessage($HANDLE, 256, KEYCODE("{F1}"))
more explained here: [Only registered and activated users can see links. Click Here To Register...]

were handle is the handle of the client window.
theres another function KEYCODE, since u need for the sendmessage the keycode and not the key.

like:
Quote:
Func Keycode($key)
If $key == "{F1}" Then
Return 112
endif
EndFunc
so just expand the keycode function with all keys and there codes...or grab them from this udf: [Only registered and activated users can see links. Click Here To Register...]

here are some more keycodes, like ur control and more:
[Only registered and activated users can see links. Click Here To Register...]

since its fast, u dont need to send the whole stroke.
just send the stroke, char by char.

have fun :)
04/11/2012 00:21 Shopko#129
LOL! :facepalm:

I wonder if dumbfck has been sitting back waiting for this moment with a smile on his face...

The question on how to actually send chat messages has already been answered in these forums [Only registered and activated users can see links. Click Here To Register...]. ROFL.

I feel so fail now. :awesome:

Thanks again guys for all the work you're doing. And dumbfck, check out my reply in your other thread about AIMLbot.
04/11/2012 09:15 Interest07#130
Another option is using the function closer to the packet sending level. Sending normal / party / trade / world chat messages is done with the function located at 0x63ab50 for example.

In c++ you can call it as follows:

Code:
sendText(0x774E00, L"I'm talking in normal chat");
sendText(0x774E01, L"I'm talking in world chat"); //requires a teleacoustic
sendText(0x774E02, L"I'm talking in party chat");
sendText(0x774E07, L"I'm talking in trade chat");
with the following declarations necessary for an injected dll:

Code:
class RealBase
{
public:
	Base* base; //0x0000 base 
};//Size=0x0004(4)

class Base
{
public:
		char unknown0[28]; //0x0000
	Structures* structures; //0x001C  
	void* packetPtr;//0x0020
		char unknown32[592]; 
	HWND hWnd; //0x0274  
		char unknown632[12]; //0x0278
	char serverAddress[100]; //0x0284  
		char unknown744[160]; //0x02E8
	char serverName[100]; //0x0388  
		char unknown1004[176]; //0x03EC
	float FPS; //0x049C  
		char unknown1184[96]; //0x04A0
};//Size=0x0500(1280)

static RealBase* realBase = (RealBase*)0xA521C0;

typedef char (__fastcall* __sendTextPacket)(void* pThis, int extra, int msgType, wchar_t* text, int int3, int int4);
static __sendTextPacket sendTextPacket = (__sendPacketFunction)0x63ab50;
static char sendText(int msgType, wchar_t* text)
{
	return sendTextPacket(realBase->base->packetPtr, 0, msgType, text, -1, -1);
}
When I was looking at the function at the time it was called with msgtypes of 0x774E00 etc, but as far as I know only the last byte matters, so 0, 1, 2, should work I think. For guild chat a different function is used (0x6477e0) but I doubt that one is really useful :p
04/11/2012 10:33 dumbfck#131
Hrm... that looks cleaner than my method - I shall have to give that a try later :D
Cheers.
04/11/2012 13:42 Interest07#132
Keep in mind that it won't show the stuff you say on your own client ;)

So have to check if it works on a second client.
04/11/2012 13:54 dumbfck#133
Hrm that rings a bell... I think I may have found a similar function to that one when I started doing the chat sending stuff then :p

For anyone wondering why that would happen, it's because when you send a message, it doesn't bounce back from the server, i.e., you don't receive your own message back - The client just echoes your message locally in the chat window.
Anyone who's played with the receiving messages stuff might have also noticed that names of items that you link in a message actually show up, whereas when someone else links an item, it just shows up as <><1>.
You need a bit more magical trickery to get those item names.
04/12/2012 09:34 Shopko#134
I've been tracing through the code for a couple of days, looking at what accesses the chat area memory in Cheat Engine and then tracing the code in Oly Debug or IDA. I don't know how you guys found these offsets, I'm very impressed. Tracing through the assembly from procedure to procedure is so painful and time-consuming. I keep feeling like there has to be a better way... :( Care to share any tips to speed up this process in the future (like when they update the client again)? :)

Thanks again for all of this information, you guys are great for sharing it with all of us.

------------------------------
INSERT MORE HOURS HERE LOL
------------------------------

Okay, I finally traced through the assembly far enough to find where the chat is actually being done. To update the original project on the first page, here are the offsets for the current elementclient (v624):

Code:
public static uint baseCall = 0xA521C0;                         // v624
public static uint playerBase = 0;                              // Calculated later
public static uint nameOffset = 0x664;                          // v624
public static uint chatObjectsBase = 0xA57A98;                  // v624
public static uint lastChatObject = 0xA57AA4;                   // v624
public static uint sendChatCall = 0x00540630;                   // v624 sendChat function address
And here is the updated sendChat op-code (only thing that changed is the address of the "speak" ASCII text):

Code:
private int sendChatOpcodeAddress;
private byte[] sendChatOpcode = new byte[]
{
    0x60,                                   // PUSHAD
    
    0xB8, 0x9C, 0x47, 0x95, 0x00,           // MOV EAX,ElementC.0095479C    ;  ASCII "speak"
    0x50,                                   // PUSH EAX
    0xBB, 0x01, 0x01, 0x00, 0x00,           // MOV EBX, 101
    0xBE, 0x00, 0x00, 0x00, 0x00,           // MOV ESI,chatSystemClassPtr   ;  [[[[[[baseCall]+1C]+18]+8]+C4]+20]
    0x8B, 0x16,                             // MOV EDX,DWORD PTR DS:[ESI]
    0x8B, 0xCE,                             // MOV ECX,ESI
    0xE8, 0x00, 0x00, 0x00, 0x00,	        // CALL sendChat()

    0x61,                                   // POPAD
    0xC3                                    // RETN
};
With these changes, it's working beautifully. Thanks so much guys!
04/12/2012 11:08 dumbfck#135
Nicely done, sir :D thanks for saving me the trouble of updating it hehe.
I'll add some finishing touches and update the first post a bit later today... well the first post in the other thread ;)
Nice to see someone new here with the enthusiasm to really get stuck in and figure this stuff out ^_^

One thing I never got around to checking last time because I wasn't familiar with the technique... I'm hoping that this call can be somehow derived from one of the function pointers in the chatbox's vTable (not sure if that's even the correct term, but that's what I'm gonna call it lol) in a similar way that the setChatText is. E.g., the setChatText() address can simply be found at [[[chatBoxBase]+0]+0x44]
I don't think the sendChat() function is directly referenced in that table, but I suspect that there's something else there that calls it :D
As another example, when I was fiddling with this last week, I think I found that the setWhisperName() func pointer is in that table, e.g., the function that inserts someone's name in the chat entry box when you click their name etc, which in turn calls the setChatText() function.

Been finding lots of cool stuff in the client ever since I found out about those tables hehe.