SIMPLE SCRIPT INJECTION – ONEACHFRAME
So I learned about OnEachFrame the other day
As you can see, all it does is take the ArmaString pointer from the argument object and put it in a global GameValue object. That’s it – that’s all OnEachFrame is. It’s a global GameValue object that has its text, if there is any, executed on each frame. So I figured, why not make a really simple executor from it?
So I learned about OnEachFrame the other day
Bağlantıları görmek için lütfen
Giriş Yap
and thought I’d take a look at it.
As you can see, all it does is take the ArmaString pointer from the argument object and put it in a global GameValue object. That’s it – that’s all OnEachFrame is. It’s a global GameValue object that has its text, if there is any, executed on each frame. So I figured, why not make a really simple executor from it?
C++:
typedef void (WINAPI* A2Free)(void*);
A2Malloc MemAlloc = *(A2Malloc*)0xDBF2A0;
A2Free MemFree = *(A2Free*)0xDBF2A4;
// To get with sig:
/*
DWORD mallocObject = DUtils::findPatternPlusBytes((DWORD)a2oaModule, (DWORD)a2LastModuleByte, "FF 15 ? ? ? ? 8B F8 85 FF 75 54", 2);
MemAlloc = *(A2Malloc*)mallocObject;
MemFree = *(A2Free*)(mallocObject + 4);*/
class ArmaString {
public:
int References;
int StringLength;
char AString[1];
// Call this to create a new ArmaString. We're basically using it as a constructor without setting up an actual Allocator for A2Malloc
static ArmaString* CreateArmaString(const char* text) {
if (!text) return 0; // you're retarded
int length = strlen(text);
ArmaString *newArmaString = (ArmaString*)MemAlloc(length + 9);
if (!newArmaString) return nullptr; // Shouldn't happen, if your MemAlloc pointer is wrong you'll crash on the call unless you get REALLY lucky
newArmaString->References = 1;
newArmaString->StringLength = length;
memcpy(&newArmaString->AString, text, length + 1);
return newArmaString;
}
};
// Kept the inheritance model in case you guys want to do things with scalars or some shit.
class GameData {
public:
void* GameDataTypeVTable;
int References;
void* DebugValueVTable;
};
class GameDataString : public GameData {
public:
ArmaString* Data;
// Calling the engine's constructor is going to be easier than manually doing our own.
typedef GameData* (__thiscall* GDConstructor)(GameData* thisptr, ArmaString* initialValue);
static GDConstructor Constructor;
GameDataString(ArmaString* initialValue) {
if (Constructor != nullptr) // If your constructor pointer is null, your object is going to be empty and you're going to crash
Constructor(this, initialValue);
References++;
}
};
// 0x9D51CB. No unique sig, other ways to find it programatically at runtime
GameDataString::GDConstructor GameDataString::Constructor = (GameDataString::GDConstructor)0x9D51CB;
class GameValue {
public:
void* GameValueVTable;
GameData* Value;
};
GameValue* OnEachFrame = (GameValue*)0xDB0614;
void InjectScript(const char* scriptText) {
ArmaString* script = ArmaString::CreateArmaString(scriptText);
GameDataString* data = new GameDataString(script);
OnEachFrame->Value = data;
}
void ExecuteScriptFile(std::string filePath) {
// execVM "filePath"; onEachFrame{};
// gotta clear the onEachFrame event since I know you tards won't do it yourselves
std::string scriptText = "execVM \"" + filePath + "\"; onEachFrame{};";
InjectScript(scriptText.c_str());
}