Avatar of ThievingSix
ThievingSix
Flag for United States of America asked on

Code Detour || Function Rerouting

Alright experts, I have been making a dll which connected to an irc server and outputs the chat to the program it was injected in.

Right now I hit a brick wall, I have the address and parameters of the function that gets called when someone types something into the program in which the dll is injected.

I would like to hook this function and reroute it to my own. I'm not to familiar with the inline asm of delphi so any help would be nice.
DelphiPascal

Avatar of undefined
Last Comment
ThievingSix

8/22/2022 - Mon
2266180

I suggest using madcodehook: http://www.madshi.net/madCodeHookDescription.htm
you've got some demos there as well. the componets are pretty easy to use and from my experience they work just fine.
I know you are using some other means of injecting but ... maybe you'll get to like madhis's components :P

(I didn't forget about the other quesiton. tab open. I just don't have anything to say yet)
ThievingSix

ASKER
Injecting the dll isn't the hard part, the code hooking is. I know madCodeHook is great. I would LOVE to use it actually. The problem is that it isn't free anymore, because of idiots that use it for virus' and malware. I have contacted madshi before about a free version, but to no avail.

I do remember seeing somewhere on here that if someone makes it into the top ten hall of fame they get it =P, but thats a long ways off for me. I'll see if his demo can be more use to me than I first thought.
2266180

I might have an old version somewhere :D
I do however have an old backed up installation. I didn't even notice that with the upgrade it was removed. but if he doesn't want it published, I don't think I should either.

you could try searching the net. at a first search, there are some older version but I don't know in which version he removed it.

start with this one: http://cc.codegear.com/partners/delphi2005/www_madshi_net/madcollection_2_1_3_5/index.html and work your way up. or if this suffice it, then enjoy :)
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
ThievingSix

ASKER
Will do the searching. As far as I know, he doesn't mind it being out, more or less he would like people to use his code. Just if it's used for the right thing.
ThievingSix

ASKER
Looks like that version works fine.

I am getting some errors though and I'm not to sure why.
procedure EntryPoint(Reason: DWORD);
begin
  If Reason = DLL_PROCESS_ATTACH Then
    begin
    HookCode(Pointer(AddressZChatInput),@ZChatInputCallBack,@ZChatInputNextHook);
  end;
end;
 
type
  TZChatOutput = procedure(Buffer: PChar; iType: Integer; iLoc: Integer; ChatColor: TColor); cdecl;
  TZChatInputNextHook = Function (Text: PChar): Boolean; cdecl;
 
var
  ZChatOutput : TZChatOutput = TZChatOutput(AddressZChatOutput);
  ZChatInputNextHook : TZChatInputNextHook;
 
procedure Echo(Output: String);
function ZChatInputCallBack(Text: PChar): Boolean; cdecl;
 
implementation
 
function ZChatInputCallBack(Text: PChar): Boolean; cdecl;
begin
  Echo('test');
  Result := ZChatInputNextHook(Text);
  //If I have the result line commented out I get buffer overrun. 
  //If it's not commented, SUB EAX,DWORD PTR DS:[ESI+20] in the callback
  //  returns an error and crashes the main app. ESI is 00000000 for some reason...
 
 
end;
 
procedure Echo(Output: String);
var
  Buffer : PChar;
begin
  If Length(Output) < 127 Then
    begin
    If @ZChatOutput <> nil Then
      begin
      GetMem(buffer, 128);
      try
        StrPCopy(Buffer,Output);
        ZChatOutput(Buffer,cmtSystem,clCurrent,$FFFFFFFF);
      finally
        FreeMem(buffer);
      end;
    end;
  end;
end;

Open in new window

ThievingSix

ASKER
Well after some calling convention changes(Don't know why this program uses two different ones for functions right next to each other), It works.

The one problem I have now is that:

function ZChatInputCallBack(Text: PChar): Boolean; stdcall;
begin
  Result := ZChatInputNextHook('asdaw');
  //or Result := ZCharInputNextHook(Text);
end;

Works and:

function ZChatInputCallBack(Text: PChar): Boolean; stdcall;
var
  Output : String;
  Buffer : PChar;
begin
  Output := '[ThievingSix] ' + Text;
  If Length(Output) > 127 Then Exit;
  GetMem(Buffer,128);
  StrPCopy(Buffer,Output);
  Result := ZChatInputNextHook(Buffer);
  FreeMem(Buffer);
end;

Doesn't.

Probably allocating wrong or something ^_^''
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
2266180

some obvious errors :P
I dont have an IDE open so I cannot tell you exactly what the parameters are, but you are old enough to figure them out :P
(plus, I just woke up like 5 min ago :D )

the problem is like this:
- if you exit the funciton without changing anthing, you MUST call ZChatInputNextHook
- you need to allocate the buffer in the same place as your program does so it can read it. you'll have to experiment with the different global/local/heap/etc allocation routines to find the right spot.
- I used reallocate as the idea, just in case the program will work with that same pchar after calling the callback. however, the problem is that if teh program passes a constant then the reallocation could fail. I don't have a definite suggestion here beside: trial and error :) but do make sure you allocate the buffer you are passing to ZChatInputNextHook in the right place. maybe make it global and change the ACLs to full for everybody (ugly but should do the trick)

and one final note: it is a good practice to code the hooking in such way that if it fails for whatever reason, it will call the original function (or implements a default behaviour that is not crashing or whatever) otherwise the hook is unstable and thus ... hate-able :)
function ZChatInputCallBack(Text: PChar): Boolean; stdcall;
var
  Output : String;
begin
  try
    Output := '[ThievingSix] ' + Text;
    If Length(Output) > 127 Then 
      Exit;
    Realloc(Text, length(output)+1);
    StrPCopy(text,Output);// make sure this overwrites text with output no matter what's in text, otherwise make text[0]:=#0 before the call. I haven't used pchar functions in ages
  finally
    Result := ZChatInputNextHook(Text);
  end;
end;

Open in new window

ThievingSix

ASKER
The code you last posted should work perfectly. I put a log in after it kept crashing.

It seems ReallocMem trips the try statement and it goes directly into the finally. It doesn't allocate it anywhere else because the Pointer to the char stays the same and so does it's contents. Which still makes me wonder why it causes the crash. Since the text passed to this is from a textbox I don't believe it to be a constant.

*continuing in second post*
function ZChatInputCallBack(Text: PChar): Boolean; stdcall;
var
  Output : String;
  F : TextFile;
begin
  AssignFile(F,'C:\ircgunz.log');
  ReWrite(F);
  Try
    Writeln(F,'Start');
    Output := '[ThievingSix] ' + Text;
    WriteLn(F,Output);
    If Length(Output) > 127 Then Exit;
    Writeln(F,'Length OK');
    Writeln(F,IntToStr(Integer(@Text)));
    ReallocMem(Text,Length(Output) + 1);
    Writeln(F,'Realloc');
    Writeln(f,Text);
    StrPCopy(Text,Output);
    Writeln(F,'copy');
    Writeln(f,Text);
  Finally
    Writeln(f,'Finally');
    Writeln(F,Text);
    Writeln(F,IntToStr(Integer(@Text)));
    CloseFile(F);
    Result := ZChatInputNextHook(Text);
  end;
end;

Open in new window

ThievingSix

ASKER
Which makes me wonder if I can just skip the original call. I would rather just call the programs ZChatOutput call myself and have the program do nothing with the text the user types in.

THe below is how it's done in c++ as far as I know.(C++ isn't my specialty).

I'm going to try the hooking method found here:https://www.experts-exchange.com/questions/22525097/Screencapture-protection.html?sfQueryTermInfo=1+hack+protect
DWORD ZChat__Input = ADDR_ZCHATINPUT;
CDetour ZChat__InputDet;
bool __stdcall ZChat__InputHook(const char* lpcLine){
	bool bRet = true;
 
	//Info
	if(stricmp(lpcLine, "!info") == 0){
		bRet = false;
		Echo("GunzHax " VERSION " Running - Written by stosw / LanceVorgin");
 
    //Unload
	}else if(stricmp(lpcLine, "!unload") == 0){
		bRet = false;
 
		Echo("GunzHax Unloading");
 
		//Here's some magic - get the original return address of the ZChat__Input caller and slap that mofo in g_dwUnloadRetAddr
		g_dwUnloadRetAddr = (DWORD)ZChat__InputDet.GetGateRetAddress();
		
		//Set the address our hook returns to to our UnloadProc
		ZChat__InputDet.SetGateRetAddress((BYTE*)UnloadProc);
 
//Respawn
}else if(stricmp(lpcLine, "!spawn") == 0){
      bRet=false;
      Repsawn();
      
//Kill
}else if(memcmp((void*)lpcLine, "!kill ", 6) == 0){
      bRet=false;
      sscanf(lpcLine, "!kill %d", &uidInput);
      uidChar->secondID=uidInput;
      ZPostGameKill(uidChar);
      
 
	
	//Are the first 7 characters "!fkmsg " ?
	}else if(memcmp((void*)lpcLine, "!fkmsg ", 7) == 0)
		//If so, replace that shit with new lines, but let the modified message be sent to the real chat handler
		memset((void*)lpcLine, '\n', 7);
 
	//Only return back to the original function (e.g. only let Gunz send the chat string) if bRet is true
	ZChat__InputDet.Ret(bRet);
 
	//Return true, telling Gunz that the string was handled (returning false will make whatever was typed stay in the box)
	return true;
}
 
typedef void (__cdecl* ZChatOutputFunc)(const char* lpcMsg, int iType /*= 0*/,int iLoc /*= 0*/,  DWORD dwColor);
ZChatOutputFunc ZChatOutput = (ZChatOutputFunc)ADDR_ZCHATOUTPUT;
void Echo(const char* lpcFmt, ...){
	char szBuf[0x4000];
	va_list vaArgs;
	va_start(vaArgs, lpcFmt);
	_vsnprintf(szBuf, sizeof(szBuf), lpcFmt, vaArgs);
	va_end(vaArgs);
	ZChatOutput(szBuf, 2, 0, 0xFFFFFFFF);
}

Open in new window

All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
ASKER CERTIFIED SOLUTION
2266180

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
ThievingSix

ASKER
Sorry for no response for a while. I'm waiting for my client to get the server up again so I can do more trials.
2266180

no problem
HuntedBounty

Theivingsix can you post your solution to this problem, i to am looking into this type of thing in delphi
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
ThievingSix

ASKER
Unfortunately I won't have my computer for about another week. What I ended up doing was edting the program manually in asm to work with the delphi dll better. I used OllyDbg to handle the registers that were messing up for some reason or another.