-
2 Attachment(s)
Chat Logger
This simply DLL will dump all the chat into a simple txt file in your folder.
There is a config.ini where you'll set the directory to save them:
Code:
[sheen_logger]
directory=Logs\\
If no dir is set, the default will be ChatLogs. It will create a txt based in the datetime:
Day-Month.txt
The chats will be saved like this:
Code:
(22:14:23) -> k: asd
H/M/S -> charName: message
Downloads: Multiupload.com - upload your files to multiple file hosting sites!
Compiled in DevC++, no source provided yet.
-- How to use it
1 - Finding the pointer
Press M, search for blah. You'll reach something like:
Code:
05CCA163 62 6C 61 68 00 00 00 00 *00 E2 14 BC 6B* 00 00 00 blah.....â¼k...
The codes between the * is the function address.
Open CFF Explorer and add the "blah" method to the import list.
Open your server.exe with olly. Control+C in the first 3 instructions and paste it to the notepad.
Go to an empty block of code in your server exe and do:
CALL DWORD PTR DS:[0x5CCA163+9]
go back to the OEP and jump to the offset of your new code.
Restore the originals codes:
PUSH 60
PUSH OFFSET
and then make a JMP to the call after the jump we made.
Clear as mud? ^_^ :thumbup:
Any ideas to make this more useful just let me know.
-
Re: Chat Logger
Awesome sauce, not because of what it does, (which is mealy "cool", not awesome sauce XD) but because of all the fantastic stuff that can be done with it.
Question: Does it log GM commands and admin authentication "chat"?
Suggestions:
- Filter other start "keywords", like ~@: etc. for local area chat, GM to all other GMs chat, enhanced GM security codes, more GM commands.
- Consider alternate logging methods, separate files... per player? According to public, private and clan chat? By field? As SQL with a log displayer which can format / filter the chat accordingly.
Question: Can it remove chat from the server before it passes it out to players?
If so, suggestions:
- Filter characters outside the codepage range for the servers default language.
- Pass every line through Google Translate and only keep lines un-translated if they are significantly similar, or use early "keywords" to allow players access to Google translate in game. Eg. "GTEn:PT est un jeu incroyable. Je l'aime." is heard "PT is an incredible game. I love it." and "GTFr:PT is an incredible game. I love it." is heard "PT est un jeu incroyable. Je l'aime." ^_^
- Apply simple obscenity filter to *** out rude words.
- Kick players who frequently say stuff that needs censoring. (rude or in the wrong language... but importantly, must be optional feature)
- Custom client locking? My client always starts every chat "Chan" and ends it "Toh", server filters it so nobody sees... if any character doesn't meet this standard they get kick banned. ^_^ (simple, but probably quite annoying for H4CK3R5)
- Apply Basefook style filters to turn :) into ☺ and <3 into ♥ etc. (I think this would appeal to the type of players PT attracts)
I have considered doing these things and more. You can probably tell. But where I have only considered, you have done.
Gratz. :thumbup1:
-
Re: Chat Logger
@bobsobol
Dunno if we can do such "hard" things. but I belive its possible now with the source provided.
Maybe just hard coding a JUMP to the end of the case block will prevent the chat to be sent? No clue.
Indeed, I just see this post after I posted this once, so I didnt have the chance to test all this.
I am not modifying the packet source here. I'm not touching the packet. I just copy it to my own variable. so, filtering words may work, but only if I change the packet itself. Which its not hard at all, but I havent done it yet. I bet you can make this now with the source =p
UPDATES:
Now compiled with VS 2010 ( I tried to stay with DEV C++, but it sucks a lot... )
Source provided now:
chat_logger.cpp
[C++] chat_logger.cpp - Pastebin.com
chat_logger.h
[C++] chat_logger.h - Pastebin.com
ini need removed since source is provided.
"new features" added:
// THE DIRECTORY TO SAVE THE LOGS
#define dir ".\\ChatLog"
// THE MAPS TO SAVE CHAT
int mapas[2] = { 3,21 };
You can limit the maps where you want the logs to be saved.
When adding new maps, dont forget to increase the loop counter in lines 35 and 68.
You can change here how the chat are dumped:
"(%d:%d:%d) -> %s (MAP: %d) \r\n" -> for normal chats only
and here
"(%d:%d:%d) -> %s: %s (TRADE MESSAGE IN MAP %d)\r\n" -> trade chats only
I didnt made party and clan chats yet. Not sure if I will though.
I'm not so skillfull in C++ so I'm sorry for any mistaked I've done.
There is a little "bug" that I dunno why is happening: when you close your server.exe, it crashes. Hope someone can help me out here.
HOW TO ADD: EASIER
The old dll was hooking recv method and seeking for 0x48471001 packet. (chat packet).
This one should be "built-in" inside the 0x48471001 case in the packets switch block.
How to find the switch:
Search for this:
Code:
00540280 /$ 55 PUSH EBP
00540281 |. 8BEC MOV EBP,ESP
00540283 |. 81EC 80030000 SUB ESP,380
00540289 |. A1 78096D00 MOV EAX,DWORD PTR DS:[6D0978]
0054028E |. 3345 04 XOR EAX,DWORD PTR SS:[EBP+4]
00540291 |. 56 PUSH ESI
00540292 |. 8B75 0C MOV ESI,DWORD PTR SS:[EBP+C]
00540295 |. 56 PUSH ESI
00540296 |. 68 58605D00 PUSH log.005D6058 ; ASCII "/TRADE>"
0054029B |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
0054029E |. E8 9A1A0100 CALL log.00551D3D
005402A3 |. 85C0 TEST EAX,EAX
005402A5 |. 59 POP ECX
005402A6 |. 59 POP ECX
005402A7 |. 74 59 JE SHORT log.00540302
005402A9 |. 83F8 64 CMP EAX,64
005402AC |. 8BC8 MOV ECX,EAX
005402AE |. 7D 1E JGE SHORT log.005402CE
Go to the offset that calls this function. scroll up a little bit.
Change the routine to this:
Code:
005471E7 > 3996 746C0000 CMP DWORD PTR DS:[ESI+6C74],EDX ; Case 48471001 of switch 00546E04
005471ED . 0F84 F40D0000 JE log.00547FE7
005471F3 . FF15 73A1CC05 CALL DWORD PTR DS:[POINTER]
005471F9 . 90 NOP
005471FA . 90 NOP
005471FB . 90 NOP
005471FC . 8A07 MOV AL,BYTE PTR DS:[EDI]
I have already explained how to find that pointer.
**WORD FILTERING** (NOT FULLY TESTED)
I will not modify the pastebin source for backup reasons.
Add this function anywhere in ur source:
Code:
void TestMessage()
{
if(strncmp(msg,"fuck",4) == 0) // his message contains fuck
show = false;
}
strncmp explanation: strncmp - C++ Reference
Add this in after the mapas[] array:
Code:
// DISPLAY THAT MESSAGE
bool show = true;
Need to call the TestMessage() method:
Code:
NAKED void Save()
{
__asm { mov _edi,EDI }
__asm { mov player_table, ESI }
memcpy(msg,_edi+0x34,100);
TestMessage();
if(msg[0] == '/')
{
DumpCommandChat();
}
else
{
DumpChat();
}
ret
}
Now some modifications in the ASM code:
back in the JUMP function, make it like this:
Code:
__asm
{
MOV EDI,a
MOV ESI,b
MOV EDX,c
ADD EDI,0x34
MOV DWORD PTR DS:[ESI+0x6C78],EDX
CMP show,0 // show is false, therefore do not broadcast this message
JE gtfo
RETN
gtfo:
mov show,1 // set the flag back to true
mov eax,*0x0547FE7*
jmp eax
}
FINDING THAT *OFFSET*
Code:
005471E7 > 3996 746C0000 CMP DWORD PTR DS:[ESI+6C74],EDX ; Case 48471001 of switch 00546E04
005471ED . 0F84 F40D0000 JE log.*00547FE7*
005471F3 . FF15 73A1CC05 CALL DWORD PTR DS:[POINTER]
Message will be "broadcasted" to the player who said this, because this is a in-game function. But other players will not see the message. So its like a: "Im talking but nobody sees, and I think they are seeing"
=p
I wasnt going to be able to sleep without doing this >.< lmfao
BAD WORD FILTER ADDED!!
The difference here is simple:
The feature above will prevent the message to be BROADCASTED. Here it will be, but with a *** string replaced.
Still, only YOU will see the original word. This screenshot speaks for me:
http://img845.imageshack.us/img845/509/badword.png
HOW TO ADD
We need to add a couple of things now:
A simply strreplace method:
Code:
char* strreplace(char* str_in, char* str_find,char* str_subst) {
char* subst_pos = strstr(str_in, str_find);
if ((subst_pos == NULL) || (strcmp(str_find, "") == 0))
return str_in;
char* result = (char*)calloc(strlen(str_in) - strlen(str_find) + strlen(str_subst) + 1, sizeof(unsigned char));
strncpy(result, str_in, subst_pos - str_in);
lstrcat(result, str_subst);
lstrcat(result, str_in + (subst_pos - str_in) + strlen(str_find));
return strreplace(result, str_find, str_subst);
}
The main function:
Code:
void ModifyPacket()
{
char* new_packet;
for(int i=0;i<2;i++)
{
char* ptr = strstr(msg,bad[i]);
if(ptr) // string found, now we create our ** string to replace
{
int len = lstrlen(bad[i]);
char* buff = (char*)malloc(len);
memset(buff,0,len);
for(int j=0;j<len;j++)
lstrcat(buff+j,"*");
new_packet = strreplace(msg,bad[i],buff);
// change the packet
memcpy(_edi+0x34,new_packet,lstrlen(new_packet));
}
}
}
with a little help of the loop and lstrcat, I generate a string, which has the same length of characters that the bad word, but with * instead.
strreplace replaces the badword with our new ** buffer.
memcpy do the tricky job: it copies the message to the packet that is about to be sent.
WHEN ADDING A NEW BADWORD, DO NOT FORGET TO INCREASE THE LOOP COUNTER!
Adding the array:
Code:
// BAD WORDS ARRAY
char* bad[2] = { "sex","mtf" };
Now, we need to call this function (ModifyPacket).
Just go to the Save() method, and add it anywhere( AFTER THE INLINE ASM INSTRUCTIONS!!!! ), but I'd say OUT of the if block:
As you can see, this stuff seems to be case-sensitive. I'm still working on that =p
I'm really excited with this :P
I never released something like this, but I just keep refreshing this page to see the comments... its kinda a good feeling lololol, I guess I know what vormav feels like when he releases something =p despite of the knoledge I'm getting with C++... I always thought this *,&, unsigned char, char were so weird.. why not to a have a simply string variable, like VB or CSharp for example =p
But IDK, I like the result when I open my dll in olly, seems exactly how pt executables looks like and after all, c++ is not so hard =p it just takes time ( a looot lol ) and a little effort on your own. Cant wait to receive some feedback on this =pp
JUST A WARNING: ANY BAD EDITIONS IN PROBABLY ANY FUNCTION WILL CAUSE THE SERVER TO CRASH IN THE EXACT MOMENT YOU TRY TO SPEAK IN PT, SO BECAREFUL WHEN MESSING WITH THE POINTERS AND THE memcpy/memset FUNCTIONS!
rectification:
There is a little "bug" that I dunno why is happening: when you close your server.exe, it crashes. Hope someone can help me out here. -> seems to be OK now, dunno why or how, buts its OK, dont mess it! lmao
-
Re: Chat Logger
Hm... I like it >=P
How about changing:
Day-Month.txt
to
Day-Month-Year.txt
?
You need to add "or" to your:
Code:
if(msg[0] == '/')
{
DumpCommandChat();
}
you can do some admin cmd with "~/".
Also you need to censure /;admin (or ~/;admin) lv1, 2, 3 commands, nobody should see password to by admin even in logs :)
-
Re: Chat Logger
Instead of strcmp(), and because we are using win32, we can use strcmpi() from user32.dll for case insensitive string comparison? ;)
-
Re: Chat Logger
:(: If I knew how to send packets to a specific player I could add that feature to kick him if he said too much rude words :(
It is possible to add commands like: /block_trade,/enable_trade and to set a flag for each player.
We just need to use the unused values in the char* player_table address.
but I dont know where server keeps the information about the player SOCKET to send packets :sleep:
@edit
@bobsobol
you mean here:
Code:
if ((subst_pos == NULL) || (lstrcmpi(str_find, "") == 0))
return str_in;
I think this is not the right place to edit to solve this... I just tested and still it only replaces sex and not SEX
-
Re: Chat Logger
Had same problem once, try using "strcasecmp" include strings.h
or try _stricmp
-
Re: Chat Logger
Dont know where to change =p
I didnt make this strreplace function, I found it online
-
Re: Chat Logger
Yes, strcmp() and strcmpi() are both C functions, not C++... so namespace conflicts can happen. :( Especially as much of user32.dll is Microsofts low level C-like (but not standard or compatible C) API.
It is one right place, but you also need to find a case insensitive strstr() routine. :/:
-
Re: Chat Logger
I just made my own function to check if a string contains another one, case insesitive.
Code:
int string_contains(char* str_in, char* str_look)
{
int len1 = lstrlen(str_in);
int len2 = lstrlen(str_look);
char* lower1 = (char*)malloc(len1);
char* lower2 = (char*)malloc(len2);
memset(lower1,0,len1);
memset(lower2,0,len2);
int i =0;
while(str_in[i])
{
lower1[i] = tolower(str_in[i]);
i++;
}
i = 0;
while(str_look[i])
{
lower2[i] = tolower(str_look[i]);
i++;
}
lower1[len1+1] = 0x00;
lower2[len2+1] = 0x00;
char* ptr = strstr(lower1,lower2);
if(ptr)
return 1;
else
return 0;
}
void TestMessage()
{
int temp = 0;
temp = string_contains(msg,"fuck");
if(temp>0) // his message contains fuck
show = false;
}
I'll implement that in my DLL and then I'll update the thread.
Bug found:
If show = false, the packet will not be sent to the other players. then, when I try to close my server, File->Exit it crashes. So, unless someone tell me whats going on, I would use the method to replace the strings with *** instead of not sending it.
Now I need to make something to replace in case insensitive...
Just found an interesting function in server.exe
Just found the function that loads the player table! it contains the char name, userid, the map he is in, the head/body model, and I belive I just found the socket number.
The function takes the charName as the only parameter. I'm just about to finish here and then I will post. with this function, we'd be able to do very great things if my guess about the socket is correct.
@edit
hohohohohohoho!!! Now I know where is the socket info, I can send packets directly to any player =p
Just tested sending me a disconnect packet and I got disconnected *--*