Raised This Month: $7 Target: $400
 1% 

how do i detour the function has variable argument?


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Zeisen
Member
Join Date: Nov 2016
Location: Republic of Korea
Old 09-30-2018 , 13:09   how do i detour the function has variable argument?
Reply With Quote #1

I'm new c++ and extension and i made my extension for some detour functions, compile/build works okay. But server does crash when PrintIfWatched detouring.

so I oversaw PrintIfWatched source-code, and i found that function uses variable argument. I have no idea how to detour that function.

and I'm sure signatures are correct.

PrintIfWatched code : https://github.com/VSES/SourceEngine...ot/bot.h#L1011

my extension.cpp
Code:
#include "extension.h"

IGameConfig *g_pGameConf;

IForward *g_pOnStopFollowing;
IForward *g_pOnSetState;
IForward *g_pOnPrintIfWatched;

CDetour *dtrStopFollowing;
CDetour *dtrSetState;
CDetour *dtrPrintIfWatched;

BotController g_BotController;

SMEXT_LINK(&g_BotController);

DETOUR_DECL_MEMBER0(StopFollowing, void)
{
	CBaseEntity *pBot = (CBaseEntity *)this;

	cell_t result = g_BotController.OnStopFollowing(pBot);
	if (result == Pl_Handled || result == Pl_Stop)
		return;

	DETOUR_MEMBER_CALL(StopFollowing)();
}

DETOUR_DECL_MEMBER1(SetState, void, cell_t, state)
{
	CBaseEntity *pBot = (CBaseEntity *)this;
	
	cell_t result = g_BotController.OnSetState(pBot, state);
	if (result == Pl_Handled || result == Pl_Stop)
		return;

	DETOUR_MEMBER_CALL(SetState)(state);
}

DETOUR_DECL_MEMBER1(PrintIfWatched, void, char *, message)
{
	CBaseEntity *pBot = (CBaseEntity *)this;

	cell_t result = g_BotController.OnPrintIfWatched(pBot, message);
	if (result == Pl_Handled || result == Pl_Stop)
		return;

	DETOUR_MEMBER_CALL(PrintIfWatched)(message);
}

bool BotController::SDK_OnLoad(char *error, size_t maxlength, bool late)
{
	if (!gameconfs->LoadGameConfigFile("bot.games", &g_pGameConf, error, maxlength))
		return false;

	g_pOnStopFollowing = g_pForwards->CreateForward("CCSBot_OnStopFollowing", ET_Hook, 1, NULL, Param_Cell);
	g_pOnSetState		= g_pForwards->CreateForward("CCSBot_OnSetState", ET_Hook, 2, NULL, Param_Cell, Param_Cell);
	g_pOnPrintIfWatched = g_pForwards->CreateForward("CCSBot_OnPrintIfWatched", ET_Hook, 2, NULL, Param_Cell, Param_String);

	CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
	
	dtrStopFollowing = DETOUR_CREATE_MEMBER(StopFollowing, "CCSBot::StopFollowing");
	if (!dtrStopFollowing)
		return false;

	dtrSetState = DETOUR_CREATE_MEMBER(SetState, "CCSBot::SetState");
	if (!dtrSetState) {
		smutils->Format(error, maxlength, "Detour failed: CCSBot::SetState");
		return false;
	}

	dtrPrintIfWatched = DETOUR_CREATE_MEMBER(PrintIfWatched, "CCSBot::PrintIfWatched");
	if (!dtrPrintIfWatched) {
		smutils->Format(error, maxlength, "Detour failed: CCSBot::PrintIfWatched");
		return false;
	}

	dtrStopFollowing->EnableDetour();
	dtrSetState->EnableDetour();
	dtrPrintIfWatched->EnableDetour();

	g_SMAPI->ConPrint("Bot Controller Extension Loaded");

	return true;
}

void BotController::SDK_OnUnload()
{
	if (dtrStopFollowing != NULL) {
		dtrStopFollowing->Destroy();
		dtrStopFollowing = NULL;
	}
	if (dtrSetState != NULL) {
		dtrSetState->Destroy();
		dtrSetState = NULL;
	}
	if (dtrPrintIfWatched != NULL) {
		dtrPrintIfWatched->Destroy();
		dtrPrintIfWatched = NULL;
	}
}

cell_t BotController::OnStopFollowing(CBaseEntity *pBot)
{
	g_pOnStopFollowing->PushCell(gamehelpers->EntityToBCompatRef(pBot));

	cell_t retValue = Pl_Continue;
	g_pOnStopFollowing->Execute(&retValue);

	return retValue;
}

cell_t BotController::OnSetState(CBaseEntity *pBot, cell_t stateAddress)
{
	g_pOnSetState->PushCell(gamehelpers->EntityToBCompatRef(pBot));
	g_pOnSetState->PushCell(stateAddress);

	cell_t retValue = Pl_Continue;
	g_pOnSetState->Execute(&retValue);

	return retValue;
}

cell_t BotController::OnPrintIfWatched(CBaseEntity *pBot, char *message)
{
	if (pBot == NULL)
		return Pl_Continue;

	cell_t pBotRef = gamehelpers->EntityToBCompatRef(pBot);
	g_SMAPI->LogMsg(g_PLAPI, "%d %s", pBotRef, message);

	g_pOnPrintIfWatched->PushCell(pBotRef);
	g_pOnPrintIfWatched->PushString(message);

	cell_t retValue = Pl_Continue;
	g_pOnPrintIfWatched->Execute(&retValue);

	return retValue;
}
and my extension.h
Code:
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_

#define CCSPlayer CBasePlayer

/**
 * @file extension.h
 * @brief Sample extension code header.
 */

#include "smsdk_ext.h"
#include "CDetour/detours.h"

/**
 * @brief Sample implementation of the SDK Extension.
 * Note: Uncomment one of the pre-defined virtual functions in order to use it.
 */
class BotController : public SDKExtension
{
public:
	/**
	 * @brief This is called after the initial loading sequence has been processed.
	 *
	 * @param error		Error message buffer.
	 * @param maxlength	Size of error message buffer.
	 * @param late		Whether or not the module was loaded after map load.
	 * @return			True to succeed loading, false to fail.
	 */
	virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
	
	/**
	 * @brief This is called right before the extension is unloaded.
	 */
	virtual void SDK_OnUnload();

	/**
	 * @brief This is called once all known extensions have been loaded.
	 * Note: It is is a good idea to add natives here, if any are provided.
	 */
	//virtual void SDK_OnAllLoaded();

	/**
	 * @brief Called when the pause state is changed.
	 */
	//virtual void SDK_OnPauseChange(bool paused);

	/**
	 * @brief this is called when Core wants to know if your extension is working.
	 *
	 * @param error		Error message buffer.
	 * @param maxlength	Size of error message buffer.
	 * @return			True if working, false otherwise.
	 */
	//virtual bool QueryRunning(char *error, size_t maxlength);
public:
#if defined SMEXT_CONF_METAMOD
	/**
	 * @brief Called when Metamod is attached, before the extension version is called.
	 *
	 * @param error			Error buffer.
	 * @param maxlength		Maximum size of error buffer.
	 * @param late			Whether or not Metamod considers this a late load.
	 * @return				True to succeed, false to fail.
	 */
	//virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late);

	/**
	 * @brief Called when Metamod is detaching, after the extension version is called.
	 * NOTE: By default this is blocked unless sent from SourceMod.
	 *
	 * @param error			Error buffer.
	 * @param maxlength		Maximum size of error buffer.
	 * @return				True to succeed, false to fail.
	 */
	//virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength);

	/**
	 * @brief Called when Metamod's pause state is changing.
	 * NOTE: By default this is blocked unless sent from SourceMod.
	 *
	 * @param paused		Pause state being set.
	 * @param error			Error buffer.
	 * @param maxlength		Maximum size of error buffer.
	 * @return				True to succeed, false to fail.
	 */
	//virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength);
#endif

	cell_t OnStopFollowing(CBaseEntity *bot);
	cell_t OnSetState(CBaseEntity *bot, cell_t stateAddress);
	cell_t OnPrintIfWatched(CBaseEntity *bot, char *message);
};

#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_

Last edited by Zeisen; 09-30-2018 at 13:15.
Zeisen is offline
Zeisen
Member
Join Date: Nov 2016
Location: Republic of Korea
Old 10-02-2018 , 22:15   Re: how do i detour the function has variable argument?
Reply With Quote #2

I'm still figuring out this. added va_list, but still crash. and buffer prints obstruction string.

Code:
DETOUR_DECL_MEMBER2(PrintIfWatched, void, char *, format, va_list *, args)
{
	CBaseEntity *pBot = (CBaseEntity *)this;

	size_t len;
	va_list ap;

	char buffer[1024];
	va_start(ap, format);
	vsprintf(buffer, format, ap);
	va_end(ap);

	g_SMAPI->ConPrintf("buffer : %s\n", buffer);

	cell_t result = g_BotController.OnPrintIfWatched(pBot, buffer);
	if (result == Pl_Handled || result == Pl_Stop)
		return;

	g_SMAPI->ConPrintf("Calling..\n");

	DETOUR_MEMBER_CALL(PrintIfWatched)(format, args);
}
Zeisen is offline
Fyren
FyrenFyrenFyrenFyrenFyren FyrenFyrenFyrenFyrenFyren FyrenFyrenFyrenFyrenFyren FyrenFyrenFyrenFyrenFyren
Join Date: Feb 2106
Old 10-03-2018 , 00:06   Re: how do i detour the function has variable argument?
Reply With Quote #3

Adding a va_list parameter isn't going to help and trying to pass one to the original function is definitely going to crash.

You might just be able to pass what you get back from vprintf (like DETOUR_MEMBER_CALL(PrintIfWatched)("%s", buffer) might work).

Last edited by Fyren; 10-03-2018 at 00:07. Reason: closing paren
Fyren is offline
hmmmmm
Great Tester of Whatever
Join Date: Mar 2017
Location: ...
Old 10-03-2018 , 01:55   Re: how do i detour the function has variable argument?
Reply With Quote #4

Make your own macro based off of DETOUR_DECL_MEMBER2 that takes the var args "..." as the second argument.
hmmmmm is offline
Zeisen
Member
Join Date: Nov 2016
Location: Republic of Korea
Old 11-11-2018 , 22:20   Re: how do i detour the function has variable argument?
Reply With Quote #5

thank you for answers, unfortunately I still couldn't figure out this. other detours works okay, but PrinfIfWatched looks something special.
Zeisen is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 01:33.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode