PDA

View Full Version : Independent c++ Unreal Engine SDK For AA 2.1 Alpha 0.5


temp2
17th October 2004, 12:19
Independent c++ Unreal Engine SDK For AA 2.1 Alpha 0.5 now exists. Preliminary additional features include:


Accounting for all objects UnrealScript makes known to C++ including ResidualClasses.cpp.
State functions.
Working out a generic way of calling pure UnrealScript functions from C++

It’s basically a huge tidy up checking nothing has been inadvertently lost and cross correlating to the working game and between the two reverse engineering mechanisms.

Email temp1290@hotmail.com with your development status, any fixes you think need making to 0.4, any tips and telling me the email address you want the 0.5.rar sent to (I will assume return-to if this is not indicated). Expected mailout on next Sunday morning GMT+10.


// State AGP.AGP_Weapon.BusyFiring
class DLL_IMPORT FBusyFiring
{
public:
/*
DECLARE_FUNCTION(execShouldDrawCrosshair); // FUNC_Defined|FUNC_Simulated|FUNC_0x00020000
{
BITFIELD ReturnValue : 1; // Offset=0x0000 CPF_Parm|CPF_OutParm|CPF_ReturnParm
}
DECLARE_FUNCTION(execStartCrawling); // FUNC_Defined|FUNC_Simulated|FUNC_0x00020000
DECLARE_FUNCTION(execBeginState); // FUNC_Defined|FUNC_Simulated|FUNC_0x00020000
*/
};

/*
DECLARE_FUNCTION(execSetOrigin); // FUNC_Final|FUNC_Defined|FUNC_0x00020000
{
FLOAT X; // Offset=0x0000 CPF_Parm
FLOAT Y; // Offset=0x0004 CPF_Parm
}
*/
DECLARE_FUNCTION(execDrawTextClipped); // FUNC_Final|FUNC_Native|FUNC_0x00020000
/*
{
class FString Text; // Offset=0x0000 CPF_Parm|CPF_CoerceParm
BITFIELD bCheckHotKey : 1; // Offset=0x000c CPF_OptionalParm|CPF_Parm
}
*/

// Texture Engine.DefaultTexture
// Texture Engine.WhiteSquareTexture
// Font Engine.DefaultFont
// Texture Engine.S_Actor
// Font Engine.SmallFont
// Texture Engine.GRADIENT_Fade
// Texture Engine.Proj_Icon
// Texture Engine.S_Emitter
// Texture Engine.S_Pawn
->
// DefaultTexture = (UTexture*)UTexture::StaticLoadObject(UTexture::St aticClass(), NULL, TEXT("Engine.DefaultTexture"), NULL, LOAD_NoFail, NULL );

megawhey
17th October 2004, 13:04
good stuff...
this can come in handy..

tanks

Rapid
17th October 2004, 15:21
why you don't ask gil to upload it to MPCDownloads ?

Shahrad
17th October 2004, 16:27
rapid, he wants to keep it to coders and coders only, probably another reaosn aswell, maybe cos pb spies cant get it or soemthin, idk

but i dont think he wants ot distrobute it publically, well not yet anyway

Rapid
17th October 2004, 21:45
hmmz ok :) no problem

Basic001
17th October 2004, 22:59
I for one am glad he's sharing it even if its only a few folks, best way to learn is from someone that knows what they are doing.

gil
17th October 2004, 23:46
He wants to give it to picked members i guess.
Anyway, he knows where to find me :)

temp2
17th October 2004, 23:47
Hookers check out http://www.madshi.net/

And just had some information about the first two fully functional aimbots generated by using the SDK ... and sniping unrendered players. Can you do that with EvilHack?

I'd like to keep the distribution mechanism as it is so only active coders get the SDK. This also means certain development techniques and topics can be discussed via more private BCC'd email. (Only I currently have all the email addresses of who I distribute to)

As we move to a beta SDK when AA:O 2.2 is released there will be a necessity to provide evidence of commitment to cheat development to join the SDK utilizing group and the current group may be asked to approve (or not) new members. If anyone has any better ideas about how engine developers can be protected please feel free to comment.

Those already developing using the SDK will of course get future SDK's.

There are so many live aimbot developments now that perhaps we ought to start a Aimbot Warfare League.

EvilHack variants
vs
Pure UnrealScript aimbots
vs
Pure Unreal Native c++ aimbots.

LOL

Arkan
18th October 2004, 00:52
Yo Temp2, Can you send that .5 vesrion to

mikeza123@comcast.net

yeah i was at that site a while back, looks good

Guess Ill post what i Go

Perfect Accuracy
No Recoil
AutoAim
AutoFire
ESP
Got some other things, nothing big

Lol.........Evilhack cant stand up to Native engine hacks

temp2
18th October 2004, 03:46
Yo Temp2, Can you send that .5 vesrion to

Perfect Accuracy
No Recoil
AutoAim
AutoFire
ESP
Got some other things, nothing big

Lol.........Evilhack cant stand up to Native engine hacks

They are dead before the EvilHack aimbot even knows you exist. Muhahahahaha.

It might be worth aimboting by choosing "best targets" according to their threat to you i.e. which player is actual aiming (weapon rotation) at you and how likely they will hit you (original accuracy of weapon). This gets a bit complex with splash damage weapons (RPG's, M203, etc...).

I also think it may be possible to construct a Grenade aimbot with lead and ping prediction. It would be so funny to throw a grenade so that it landed in front of where a target had run to and exploded after say a 1 second delay allowing them to appreciate their predicament and forthcoming death.

Arkan
18th October 2004, 06:25
That would be tight, read your pms, i sent a reply, If you want to code some stuff, that would be cool

-=UnKnOwN=-
18th October 2004, 06:43
arkan you don't have an engine hack...... come on stop dreaming and lieing

Arkan
18th October 2004, 09:30
Ah Unknown, we need to play sometime. You can use your evilhack I will use what I choose

"Ignorance is bliss"

gil
18th October 2004, 11:57
I saw arkan playing, what i know its that he doesnt use EH mod.
I dont know if its Engine hack or AAOM but it was pretty neat ;)

temp2
18th October 2004, 13:59
I saw arkan playing, what i know its that he doesnt use EH mod.
I dont know if its Engine hack or AAOM but it was pretty neat ;)

Many engine hack features look like devmode or AAOM. In fact devmode and AAOM developments are very useful for the engine hackers because they then know exactly what properties of what classes to modify to what effect.

I actually doubt if Arkan has not got an engine hack since example.cpp in the SDK contains most of one. When I have figured out a generic way of calling virtual functions it will be fully functional though simple (no lead or ping correction).

As a side note I hear Helios Radar 6.2 has been packaged up by p1p0 and is being tested.

temp2
18th October 2004, 22:56
I'm considering what is the best generic way to represent virtual functions in the SDK. To get functions working is a matter of mapping virtual function calls to prototypes. eg. What I might do is provide something like the following in the headers. But that will mean thousands of assignments which is not a problem in itself but may look unwieldy. Any thoughts on what you like and what seems most useful? I could just provide an example and allow coders to code what functions they need?

typedef void(__cdecl *VirtualFunctionType)();
VirtualFunctionType VirtualFunction;
VirtualFunction =
(VirtualFunctionType)GetProcAddress(GetModuleHandl e("Module"),
"DecoratedName");
VirtualFunction();

Arkan
18th October 2004, 23:06
Yo, Temp2 PM me with your msn, or instant messenger so i can talk with yo. Got some questions, and the PM system takse to long

I also sent a email to your reply

temp2
19th October 2004, 04:14
Yo, Temp2 PM me with your msn, or instant messenger so i can talk with yo. Got some questions, and the PM system takse to long

I also sent a email to your reply

Best way to contact me is via email or sometime between 9-11 GMT on [ELF] irc.

Had a very interesting chat with HeliOs. Here is some code which is my experiments with solving this virtuals problem. Though I have a better way so these techniques will only be used as a fallback but should get you going.


void (WINAPI * WrappedPrintf2)(class UFont *,INT,TCHAR const *,...) = ((void(WINAPI *)(class UFont *,INT,TCHAR const *,...))0x00273788);

typedef void(WINAPI *WrappedPrintf_typedef)(class UFont *,INT,TCHAR const *,...);
WrappedPrintf_typedef WrappedPrintf3 = (WrappedPrintf_typedef)0x00273788;


void Testing ()
{
WrappedPrintf_typedef WrappedPrintf;
HINSTANCE DllInstance;

if ((DllInstance = GetModuleHandleA("Engine.dll")) == NULL)
{
if ((DllInstance = LoadLibraryA("Engine.dll")) == NULL)
{
GLog->Logf(TEXT("Engine.dll cannot be located"));
}
}
if (DllInstance != NULL)
{
GLog->Logf(TEXT("Engine.dll at 0x%08x "),(DWORD)DllInstance);
if((WrappedPrintf = (WrappedPrintf_typedef)GetProcAddress(DllInstance,"?WrappedPrintf@UCanvas@@UAAXPAVUFont@@MMHPBGZZ")) == NULL)
{
GLog->Logf(TEXT("?WrappedPrintf@UCanvas@@UAAXPAVUFont@@MMHPBGZZ cannot be located"));
}
else
{
GLog->Logf(TEXT("?WrappedPrintf@UCanvas@@UAAXPAVUFont@@MMHPBGZZ at 0x%08x "),(DWORD)WrappedPrintf);
}
}
}


With 2.2 is is going to be come harder to join the coding band and download slots permitting 0.5 may be a 2.2. release.

Picklelicious
22nd October 2004, 00:14
I'm considering what is the best generic way to represent virtual functions in the SDK. …I am trying to get the virtual functions too. What you are thinking of doing is not going to work. Virtual functions are special in that they are not directly called; they are called via the VMT (virtual method table, basically a table of function pointers). Descendent classes can replace the virtual functions by changing the function pointers in the VMT.

Your virtual function definitions are going to have to have the virtual keyword and look like:
virtual void foo(void);

I am pretty sure the VMT is filled in the order the virtual functions are declared in the class. It should be possible to compare the virtual function address to the VMT to figure out the correct order for the VMT.

Right now my UObject looks like this (the virtual functions are not in the correct order yet):


class UObject //0x0000 0x640F0004
{
public:
int ObjectInternal[6]; //0x0000 0x00001002
UObject * Outer; //0x0018 0x00001002
int ObjectFlags; //0x001C 0x00001002
FName Name; //0x0020 0x00021003
UClass * Class; //0x0024 0x00021002

virtual ~UObject(void);
virtual unsigned long __stdcall AddRef(void);
virtual int AllowGarbageCollection(void);
virtual void CallFunction(FFrame &,void * const,UFunction *);
virtual void Destroy(void);
virtual int GotoLabel(FName);
virtual EGotoState GotoState(FName);
virtual void InitExecution(void);
virtual int IsPendingKill(void);
virtual void LanguageChange(void);
virtual void Modify(void);
virtual void NetDirty(UProperty *);
virtual void PostEditChange(void);
virtual void PostLoad(void);
virtual void ProcessDelegate(FName,FScriptDelegate *,void *,void *);
virtual void ProcessEvent(UFunction *,void *,void *);
virtual int ProcessRemoteFunction(UFunction *,void *,FFrame *);
virtual void ProcessState(float);
virtual unsigned long __stdcall QueryInterface(FGuid const &,void **);
virtual void Register(void);
virtual unsigned long __stdcall Release(void);
virtual void Rename(unsigned short const *,UObject *);
virtual int ScriptConsoleExec(unsigned short const *,FOutputDevice &,UObject *);
virtual void Serialize(FArchive &);
virtual void ShutdownAfterError(void);

static void * __cdecl operator new(unsigned int,UObject *,FName,unsigned long);
static void * __cdecl operator new(unsigned int,EInternal *);
static void __cdecl operator delete(void *,unsigned int);
static int __cdecl AttemptDelete(UObject * &,unsigned long,int);
static void __cdecl BeginLoad(void);
static void __cdecl BindPackage(UPackage *);
static void __cdecl CacheDrivers(int);
static void __cdecl CheckDanglingOuter(UObject *);
static void __cdecl CheckDanglingRefs(UObject *);
static void __cdecl CollectGarbage(unsigned long);
static UPackage * __cdecl CreatePackage(UObject *,unsigned short const *);
static void __cdecl EndLoad(void);
static void __cdecl ExitProperties(unsigned char *,UClass *);
static void __cdecl ExportProperties(FOutputDevice &,UClass *,unsigned char *,int,UClass *,unsigned char *);
static UObject * __cdecl GetIndexedObject(int);
static int __cdecl GetInitialized(void);
static unsigned short const * __cdecl GetLanguage(void);
static ULinkerLoad * __cdecl GetLoader(int);
static TArray<UObject *> __cdecl GetLoaderList(void);
static int __cdecl GetObjectHash(FName,int);
static ULinkerLoad * __cdecl GetPackageLinker(UObject *,unsigned short const *,unsigned long,UPackageMap *,FGuid *);
static void __cdecl GetPreferences(TArray<FPreferencesInfo> &,unsigned short const *,int);
static void __cdecl GetRegistryObjects(TArray<FRegistryObjectInfo> &,UClass *,UClass *,int);
static UPackage * __cdecl GetTransientPackage(void);
static void __cdecl GlobalSetProperty(unsigned short const *,UClass *,UProperty *,int,int);
static void __cdecl InitProperties(unsigned char *,int,UClass *,unsigned char *,int,UObject *,UObject *);
static void __cdecl InternalConstructor(void *);
static int __cdecl IsReferenced(UObject * &,unsigned long,int);
static UObject * __cdecl LoadPackage(UObject *,unsigned short const *,unsigned long);
static FName __cdecl MakeUniqueObjectName(UObject *,UClass *);
static void __cdecl ProcessRegistrants(void);
static void __cdecl PurgeGarbage(void);
static void __cdecl ResetConfig(UClass *);
static void __cdecl ResetLoaders(UObject *,int,int);
static int __cdecl ResolveName(UObject * &,unsigned short const * &,int,int);
static void __cdecl SafeLoadError(unsigned long,unsigned short const *,unsigned short const *,...);
static int __cdecl SavePackage(UObject *,UObject *,unsigned long,unsigned short const *,FOutputDevice *,ULinkerLoad *);
static void __cdecl SerializeRootSet(FArchive &,unsigned long,unsigned long);
static void __cdecl SetLanguage(unsigned short const *);
static UObject * __cdecl StaticAllocateObject(UClass *,UObject *,FName,unsigned long,UObject *,FOutputDevice *,UObject *,UObject *);
static UClass * __cdecl StaticClass(void);
static unsigned short const * __cdecl StaticConfigName(void);
static UObject * __cdecl StaticConstructObject(UClass *,UObject *,FName,unsigned long,UObject *,FOutputDevice *,UObject *);
static int __cdecl StaticExec(unsigned short const *,FOutputDevice &);
static void __cdecl StaticExit(void);
static UObject * __cdecl StaticFindObject(UClass *,UObject *,unsigned short const *,int);
static UObject * __cdecl StaticFindObjectChecked(UClass *,UObject *,unsigned short const *,int);
static void __cdecl StaticInit(void);
static UClass * __cdecl StaticLoadClass(UClass *,UObject *,unsigned short const *,unsigned short const *,unsigned long,UPackageMap *);
static UObject * __cdecl StaticLoadObject(UClass *,UObject *,unsigned short const *,unsigned short const *,unsigned long,UPackageMap *);
static void __cdecl StaticShutdownAfterError(void);
static void __cdecl StaticTick(void);
static void __cdecl VerifyLinker(ULinkerLoad *);

UObject(UObject const &);
UObject(EInPlaceConstructor,UClass *,UObject *,FName,unsigned long);
UObject(ENativeConstructor,UClass *,unsigned short const *,unsigned short const *,unsigned long);
UObject(EStaticConstructor,unsigned short const *,unsigned short const *,unsigned long);
UObject(void);
UObject & operator=(UObject const &);
void AddObject(int);
void AddToRoot(void);
void ClearFlags(unsigned long);
int ConditionalDestroy(void);
void ConditionalPostLoad(void);
void ConditionalRegister(void);
void ConditionalShutdownAfterError(void);
int FindArrayProperty(FString,FArray **,int *);
int FindBoolProperty(FString,int *);
int FindFNameProperty(FString,FName *);
int FindFloatProperty(FString,float *);
UFunction * FindFunction(FName,int);
UFunction * FindFunctionChecked(FName,int);
int FindIntProperty(FString,int *);
UField * FindObjectField(FName,int);
int FindObjectProperty(FString,UObject **);
UState * FindState(FName);
int FindStructProperty(FString,UStruct **);
UClass * GetClass(void)const ;
FName const GetFName(void)const ;
unsigned long GetFlags(void)const ;
unsigned short const * GetFullName(unsigned short *)const ;
unsigned long GetIndex(void)const ;
ULinkerLoad * GetLinker(void);
int GetLinkerIndex(void);
unsigned short const * GetName(void)const ;
UObject * GetOuter(void)const ;
unsigned short const * GetPathName(UObject *,unsigned short *)const ;
FStateFrame * GetStateFrame(void);
void HashObject(void);
void InitClassDefaultObject(UClass *,int);
int IsA(UClass *)const ;
int IsIn(UObject *)const ;
int IsInState(FName);
int IsProbing(FName);
int IsValid(void);
void LoadConfig(int,UClass *,unsigned short const *);
void LoadLocalized(void);
void ParseParms(unsigned short const *);
void ProcessInternal(FFrame &,void * const);
void RemoveFromRoot(void);
void SaveConfig(unsigned long,unsigned short const *);
void SetClass(UClass *);
void SetFlags(unsigned long);
void SetLinker(ULinkerLoad *,int);
void StaticConstructor(void);
void UnhashObject(int);
void eventBeginState(void);
void eventEndState(void);
void execAbs(FFrame &,void * const);
void execAcos(FFrame &,void * const);
void execAddAdd_Byte(FFrame &,void * const);
void execAddAdd_Int(FFrame &,void * const);
….
}; //0x0028

temp2
22nd October 2004, 01:28
I am trying to get the virtual functions too. What you are thinking of doing is not going to work. Virtual functions are special in that they are not directly called; they are called via the VMT (virtual method table, basically a table of function pointers). Descendent classes can replace the virtual functions by changing the function pointers in the VMT.

Your virtual function definitions are going to have to have the virtual keyword and look like:
virtual void foo(void);

I am pretty sure the VMT is filled in the order the virtual functions are declared in the class. It should be possible to compare the virtual function address to the VMT to figure out the correct order for the VMT.

Right now my UObject looks like this (the virtual functions are not in the correct order yet):


I think I've already figured out how to extract the virtual functions in the correct order as per defined in the dll (still got a couple of bugs with it but the concepts working) (fig 1) but that now itself is posing problems for the SDK. The primary one being that the undecorated dll defined class order must become the driver for class decomposition (fairly easy), that certain classes not referred to via UnrealScript decomposition need integrating into the order because they themselves sometimes have virtual functions (fairly easy) (fig 2)

cont...

(fig 1)

FArchive
FArchiveCountMem
FArchiveDummySave
FBitReader
FBitScrambleArchiveReader
FBitScrambleArchiveWriter
FBitWriter
FBufferReader
FCommonWindowsFileArchive
FWindowsFileReader
FWindowsFileWriter
UArrayProperty
UBoolProperty
UByteProperty
UClass
UClassProperty
UCommandlet
UConst
UDelegateProperty
UEnum
UExporter
UFactory
UField
UFixedArrayProperty
UFloatProperty
UFunction
UIntProperty
ULanguage
ULinker
UMapProperty
UNameProperty
UObject
UObjectExporterT3D
UObjectProperty
UPackage
UPackageMap
UProperty
UState
UStrProperty
UStruct
UStructProperty
USubsystem
USystem
UTextBuffer
UTextBufferFactory


(fig 2)

// ************************************************** ***************************
// FArchive
// ************************************************** ***************************
//

class DLL_IMPORT FArchive
{
public:
class FArchive & ByteOrderSerialize(void *,INT);
int ContainsCode();
FArchive(class FArchive const &);
FArchive();
int ForClient();
int ForEdit();
int ForServer();
int IsCriticalError();
int IsError();
int IsLoading();
int IsNet();
int IsPersistent();
int IsSaving();
int IsTrans();
int LicenseeVer();
int NetVer();
void ThisContainsCode();
int Ver();
class FArchive & operator=(class FArchive const &);
virtual INT MapName(class FName *);
virtual INT MapObject(class UObject *);
virtual void Seek(INT);
virtual INT Tell();
virtual void Serialize(void *,INT);
virtual void SerializeBits(void *,INT);
virtual void SerializeInt(unsigned long &,DWORD);
virtual INT GetError();
virtual void SetStopper(INT);
virtual void DetachLazyLoader(class FLazyLoader *);
virtual INT Close();
virtual void Flush();
virtual INT TotalSize();
virtual void CountBytes(DWORD,DWORD);
virtual class FArchive & operator<<(class FName &);
virtual class FArchive & operator<<(class UObject * &);
virtual void Precache(INT);
virtual void Preload(class UObject *);
virtual INT AtEnd();
virtual INT AtStopper();
virtual void AttachLazyLoader(class FLazyLoader *);
};


What you are thinking of doing is not going to work

But the biggie seem to be that its going to be a matter of pure faith having done this i.e

correctly ordered the classes
correctly ordered the virtuals within the class

That this then means all virtual functions will appear in the correct order in the dll. Mainly the virtual functions of a derived class appear to have their function definitions immediately after the function definitions of the super class (fig 3. Virtual function order from core.dll). But sometimes as per (fig 3.) something else appears to be going on like why did UArrayProperty::AddCppProperty pop into the picture so soon..., etc...

This currently leads me to the idea of temporarily utilizing a bodge like :

typedef void(WINAPI *WrappedPrintf_typedef)(class UFont *,INT,TCHAR const *,...);
WrappedPrintf_typedef WrappedPrintf3 = (WrappedPrintf_typedef)0x00273788;

void (WINAPI * WrappedPrintf)(class UFont *,INT,TCHAR const *,...) = ((void(WINAPI *)(class UFont *,INT,TCHAR const *,...))0x00273788);


Which should get people going, but I'm not sure if direct (0x00273788) addressing will be portable across machines / OS's and may have to become something like GetProcAddress(DllInstance,DecoratedName). I really can't see why that should not work as that is exactly the way IAT hooking works ... except there is no redirection. The problem with that is that of course certain AC programs hook GetProcAddress to see what is being used for an by.

(fig 3.)

public: virtual class FArchive & FArchive::operator<<(class UObject * &);
public: virtual class FArchive & FArchive::operator<<(class FName &);
public: virtual void UArrayProperty::AddCppProperty(class UProperty *);
public: virtual void UField::AddCppProperty(class UProperty *);
public: virtual void UStruct::AddCppProperty(class UProperty *);
public: virtual INT UPackageMap::AddLinker(class ULinkerLoad *);
public: virtual DWORD __stdcall FUnknown::AddRef();
public: virtual DWORD __stdcall UObject::AddRef();
public: virtual INT UObject::AllowGarbageCollection();
public: virtual INT FArchive::AtEnd();
public: virtual INT FBitReader::AtEnd();
public: virtual INT FBufferReader::AtEnd();
public: virtual INT FArchive::AtStopper();
public: virtual void FCommonWindowsFileArchive::Attach(void *);
public: virtual void FArchive::AttachLazyLoader(class FLazyLoader *);
public: virtual void UClass::Bind();
public: virtual void UField::Bind();
public: virtual void UFunction::Bind();
public: virtual TCHAR const * FFileManager::CalcHomeDir();
public: virtual void UObject::CallFunction(struct FFrame &,void * const,class UFunction *);
public: virtual INT UPackageMap::CanSerializeObject(class UObject *);
public: virtual void UArrayProperty::CleanupDestroyed(unsigned char *)const ;
public: virtual void UDelegateProperty::CleanupDestroyed(unsigned char *)const ;
public: virtual void UFixedArrayProperty::CleanupDestroyed(unsigned char *)const ;
public: virtual void UObjectProperty::CleanupDestroyed(unsigned char *)const ;
public: virtual void UProperty::CleanupDestroyed(unsigned char *)const ;
public: virtual void UStruct::CleanupDestroyed(unsigned char *);
public: virtual void UStructProperty::CleanupDestroyed(unsigned char *)const ;
public: virtual INT FArchive::Close();
public: virtual INT FCommonWindowsFileArchive::Close();
public: virtual void UPackageMap::Compute();

Picklelicious
22nd October 2004, 17:19
I think I've already figured out how to extract the virtual functions in the correct order as per defined in the dll.It looks like you used the order which the dll exported the functions. (The dll exports are in alphabetical order.) That is not going to be the same as the order in which the virtual functions were declared.

Here is an example. Here we have two classes with the virtual functions declared in reverse alphabetical order:

class _declspec(dllexport) Class1
{
public:
virtual ~Class1(void);

virtual void Z(void);
virtual void A(void);

int X;
};

Class1::~Class1(void) {X=1;}
void Class1::Z(void) {X=2;}
void Class1::A(void) {X=3;}

class _declspec(dllexport) Class2 : public Class1
{
public:
virtual ~Class2(void);

virtual void B(void);
virtual void Z(void);
};

Class2::~Class2(void) {X=4;}
void Class2::Z(void) {X=5;}
void Class2::B(void) {X=6;}
Here are the VMT’s that the compiler created (extracted with IDAPro from the copmiled dll):

.rdata:100060D0 ; Exported entry 9. ??_7Class1@@6B@
.rdata:100060D0 public ??_7Class1@@6B@
.rdata:100060D0 ; const Class1::`vftable'
.rdata:100060D0 ??_7Class1@@6B@ dd offset sub_10001040
.rdata:100060D4 dd offset ?Z@Class1@@UAEXXZ ; Class1::Z(void)
.rdata:100060D8 dd offset ?A@Class1@@UAEXXZ ; Class1::A(void)


.rdata:100060DC ; Exported entry 10. ??_7Class2@@6B@
.rdata:100060DC public ??_7Class2@@6B@
.rdata:100060DC ; const Class2::`vftable'
.rdata:100060DC ??_7Class2@@6B@ dd offset sub_10001100
.rdata:100060E0 dd offset ?Z@Class2@@UAEXXZ ; Class2::Z(void)
.rdata:100060E4 dd offset ?A@Class1@@UAEXXZ ; Class1::A(void)
.rdata:100060E8 dd offset ?B@Class2@@UAEXXZ ; Class2::B(void) You can see all the virtual functions appear in the order they were declared – reverse alphabetical, oldest classes first. Using dumpbin, we can see the order the functions were exported:

ordinal hint RVA name

1 0 00001010 ??0Class1@@QAE@ABV0@@Z
2 1 00001000 ??0Class1@@QAE@XZ
3 2 000010E0 ??0Class2@@QAE@ABV0@@Z
4 3 000010D0 ??0Class2@@QAE@XZ
5 4 000010A0 ??1Class1@@UAE@XZ
6 5 00001160 ??1Class2@@UAE@XZ
7 6 00001030 ??4Class1@@QAEAAV0@ABV0@@Z
8 7 00001030 ??4Class2@@QAEAAV0@ABV0@@Z
9 8 000060D0 ??_7Class1@@6B@
10 9 000060DC ??_7Class2@@6B@
11 A 000010C0 ?A@Class1@@UAEXXZ
12 B 00001190 ?B@Class2@@UAEXXZ
13 C 000010B0 ?Z@Class1@@UAEXXZ
14 D 00001180 ?Z@Class2@@UAEXXZ They are exported alphabetically. To have any chance of getting it right, you are going to have to get the VMT (which are exported as ??_7<class>@@XXXX) and order your virtual functions in that order. Also notice that Class1::A() was not declared in Class2, but it is in Class2’s VMT.


Which should get people going, but I'm not sure if direct (0x00273788) addressing will be portable across machines / OS's and may have to become something like GetProcAddress(DllInstance,DecoratedName).I don’t think you should have to call GetProcAddress. All you need to do is create a correct *.h file and a *.lib file from the DLL. Then compile with the *.h and link with the *.lib. All the addressing will get resolved when the dll loads.


The problem with that is that of course certain AC programs hook GetProcAddress to see what is being used for an by.Then don’t call GetProcAddress. All GetProcAddress does is gets an addess from from a loaded dll's EAT (export address table). Just go get it yourself.

/************************************************** **************************
*
* DirectGetProcAddress(hDll, pProcName) : pProc
* hDll - Module handle of the dll.
* pProcName - Name or ordinal of the proc.
* pProc - Address of the function.
*
* DirectGetProcAddress is just like GetProcAddress.
*
************************************************** **************************/
FARPROC DirectGetProcAddress(HMODULE hModule, LPCSTR pProcName)
{
DWORD Index;
DWORD MaxAdd;
DWORD MinAdd;
char * pChar;
PIMAGE_DOS_HEADER pDOSHeader;
PIMAGE_EXPORT_DIRECTORY pExportDir;
DWORD * pDWORD;
PIMAGE_NT_HEADERS pNTHeader;
FARPROC pProc;
WORD * pWORD;


//Validate the input.
if (!hModule || !pProcName)
return(0);


try
{
//Get the EAT.
pDOSHeader = (PIMAGE_DOS_HEADER)hModule;
if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
return(0);

pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDOSHeader, pDOSHeader->e_lfanew);
if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
return(0);

if (!pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].
VirtualAddress)
{
return(0);
}

pExportDir = MakePtr(PIMAGE_EXPORT_DIRECTORY, pDOSHeader,
pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);


//Search the EAT.
if ((DWORD)pProcName & 0xFFFF0000)
{
pDWORD = MakePtr(LPDWORD, pDOSHeader, pExportDir->AddressOfNames);
for (Index = 0; Index < pExportDir->NumberOfNames; ++Index)
{
pChar = MakePtr(char *, pDOSHeader, pDWORD[Index]);
if (!stricmp(pProcName, pChar))
break;
}
if (Index >= pExportDir->NumberOfNames)
return(0);

pWORD = MakePtr(LPWORD, pDOSHeader, pExportDir->AddressOfNameOrdinals);
Index = pWORD[Index] + pExportDir->Base;
}

else
{
Index = (DWORD)pProcName;
}


//Return the offset to the function.
pDWORD = MakePtr(LPDWORD, pDOSHeader, pExportDir->AddressOfFunctions);
pProc = MakePtr(FARPROC, pDOSHeader, pDWORD[Index - pExportDir->Base]);


//Check to see if this is a forwarder. A forwarder points to
//DLLName.FunctionName\0
MinAdd = MakePtr(DWORD, pDOSHeader,
pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
MaxAdd = MakePtr(DWORD, MinAdd,
pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size);
if (((DWORD)pProc >= MinAdd) && ((DWORD)pProc <= MaxAdd))
{
char Line[MAX_PATH];
char * pChar;


strcpy(Line, (char *)pProc);
pChar = Line;
while (*pChar && (*pChar != '.'))
++pChar;
if (!*pChar)
return(0);

*pChar = 0;
++pChar;

hModule = GetModuleHandle(Line);
if (!hModule)
return(0);

pProc = DirectGetProcAddress(hModule, pChar);
}

return(pProc);
}

catch (...)
{
Log("EXCEPTION DirectGetProcAddress");
return(0);
}
}

HelioS
22nd October 2004, 19:18
This is my output

class DLL_IMPORT UObject : public FUnknown
{
public:
INT ObjectInternal[6];
class UObject* Outer;
INT ObjectFlags;
FName Name;
class UClass* Class;

UObject(UObject const &);
UObject(enum EInPlaceConstructor,UClass *,UObject *,FName,unsigned long);
UObject(enum ENativeConstructor,UClass *,unsigned short const *,unsigned short const *,unsigned long);
UObject(enum EStaticConstructor,unsigned short const *,unsigned short const *,unsigned long);
UObject(void);
static void * operator new(unsigned int,UObject *,FName,unsigned long);
static void * operator new(unsigned int,enum EInternal *);
static void operator delete(void *,unsigned int);
UObject & operator=(UObject const &);
void AddToRoot(void);
static int AttemptDelete(UObject * &,unsigned long,int);
static void BeginLoad(void);
static void BindPackage(UPackage *);
static void CheckDanglingOuter(UObject *);
static void CheckDanglingRefs(UObject *);
void ClearFlags(unsigned long);
static void CollectGarbage(unsigned long);
int ConditionalDestroy(void);
void ConditionalPostLoad(void);
void ConditionalRegister(void);
void ConditionalShutdownAfterError(void);
static UPackage * CreatePackage(UObject *,unsigned short const *);
static void EndLoad(void);
static void ExitProperties(unsigned char *,UClass *);
static void ExportProperties(FOutputDevice &,UClass *,unsigned char *,int,UClass *,unsigned char *);
int FindArrayProperty(FString,FArray * *,int *);
int FindBoolProperty(FString,int *);
int FindFNameProperty(FString,FName *);
int FindFloatProperty(FString,float *);
UFunction * FindFunction(FName,int);
UFunction * FindFunctionChecked(FName,int);
int FindIntProperty(FString,int *);
UField * FindObjectField(FName,int);
int FindObjectProperty(FString,UObject * *);
UState * FindState(FName);
int FindStructProperty(FString,UStruct * *);
UClass * GetClass(void)const ;
FName const GetFName(void)const ;
unsigned long GetFlags(void)const ;
unsigned short const * GetFullName(unsigned short *)const ;
unsigned long GetIndex(void)const ;
static UObject * GetIndexedObject(int);
static int GetInitialized(void);
static unsigned short const * GetLanguage(void);
ULinkerLoad * GetLinker(void);
int GetLinkerIndex(void);
static TArray<UObject *> GetLoaderList(void);
unsigned short const * GetName(void)const ;
static int GetObjectHash(FName,int);
UObject * GetOuter(void)const ;
static ULinkerLoad * GetPackageLinker(UObject *,unsigned short const *,unsigned long,UPackageMap *,FGuid *);
unsigned short const * GetPathName(UObject *,unsigned short *)const ;
static void GetPreferences(TArray<FPreferencesInfo> &,unsigned short const *,int);
static void GetRegistryObjects(TArray<FRegistryObjectInfo> &,UClass *,UClass *,int);
struct FStateFrame * GetStateFrame(void);
static UPackage * GetTransientPackage(void);
static void GlobalSetProperty(unsigned short const *,UClass *,UProperty *,int,int);
void InitClassDefaultObject(UClass *,int);
static void InitProperties(unsigned char *,int,UClass *,unsigned char *,int,UObject *,UObject *);
static void InternalConstructor(void *);
int IsA(UClass *)const ;
int IsIn(UObject *)const ;
int IsInState(FName);
int IsProbing(FName);
static int IsReferenced(UObject * &,unsigned long,int);
int IsValid(void);
void LoadConfig(int,UClass *,unsigned short const *);
void LoadLocalized(void);
static UObject * LoadPackage(UObject *,unsigned short const *,unsigned long);
void ParseParms(unsigned short const *);
void ProcessInternal(struct FFrame &,void * const);
static void ProcessRegistrants(void);
void RemoveFromRoot(void);
static void ResetConfig(UClass *);
static void ResetLoaders(UObject *,int,int);
void SaveConfig(unsigned long,unsigned short const *);
static int SavePackage(UObject *,UObject *,unsigned long,unsigned short const *,FOutputDevice *,ULinkerLoad *);
static void SerializeRootSet(FArchive &,unsigned long,unsigned long);
void SetClass(UClass *);
void SetFlags(unsigned long);
static void SetLanguage(unsigned short const *);
static UObject * StaticAllocateObject(UClass *,UObject *,FName,unsigned long,UObject *,FOutputDevice *,UObject *,UObject *);
static UClass * StaticClass(void);
static unsigned short const * StaticConfigName(void);
static UObject * StaticConstructObject(UClass *,UObject *,FName,unsigned long,UObject *,FOutputDevice *,UObject *);
void StaticConstructor(void);
static int StaticExec(unsigned short const *,FOutputDevice &);
static void StaticExit(void);
static UObject * StaticFindObject(UClass *,UObject *,unsigned short const *,int);
static UObject * StaticFindObjectChecked(UClass *,UObject *,unsigned short const *,int);
static void StaticInit(void);
static UClass * StaticLoadClass(UClass *,UObject *,unsigned short const *,unsigned short const *,unsigned long,UPackageMap *);
static UObject * StaticLoadObject(UClass *,UObject *,unsigned short const *,unsigned short const *,unsigned long,UPackageMap *);
static void StaticShutdownAfterError(void);
static void StaticTick(void);
static void VerifyLinker(ULinkerLoad *);
unsigned short const * const `static void operator delete(void *,unsigned int)'::`3'::__FUNC_NAME__;

....

virtual unsigned long QueryInterface(FGuid const &,void * *);
virtual unsigned long AddRef(void);
virtual unsigned long Release(void);
virtual ~UObject(void);
virtual void ProcessEvent(UFunction *,void *,void *);
virtual void ProcessDelegate(FName,struct FScriptDelegate *,void *,void *);
virtual void ProcessState(float);
virtual int ProcessRemoteFunction(UFunction *,void *,struct FFrame *);
virtual void Modify(void);
virtual void PostLoad(void);
virtual void Destroy(void);
virtual void Serialize(FArchive &);
virtual int IsPendingKill(void);
virtual enum EGotoState GotoState(FName);
virtual int GotoLabel(FName);
virtual void InitExecution(void);
virtual void ShutdownAfterError(void);
virtual void PostEditChange(void);
virtual void CallFunction(struct FFrame &,void * const,UFunction *);
virtual int ScriptConsoleExec(unsigned short const *,FOutputDevice &,UObject *);
virtual void Register(void);
virtual void LanguageChange(void);
virtual void Rename(unsigned short const *,UObject *);
virtual void NetDirty(UProperty *);
virtual int AllowGarbageCollection(void);
private:
void AddObject(int);
static void CacheDrivers(int);
static UObject * GAutoRegister;
static int GImportCount;
static unsigned short * GLanguage;
static TArray<int> GObjAvailable;
static int GObjBeginLoadCount;
static unsigned short * GObjCachedLanguage;
static TArray<FRegistryObjectInfo> GObjDrivers;
static UObject * * GObjHash;
static int GObjInitialized;
static TArray<UObject *> GObjLoaded;
static TArray<UObject *> GObjLoaders;
static int GObjNoRegister;
static TArray<UObject *> GObjObjects;
static TMultiMap<FName,FName> * GObjPackageRemap;
static TArray<FPreferencesInfo> GObjPreferences;
static int GObjRegisterCount;
static TArray<UObject *> GObjRegistrants;
static TArray<UObject *> GObjRoot;
static UPackage * GObjTransientPkg;
static ULinkerLoad * GetLoader(int);
void HashObject(void);
static FName MakeUniqueObjectName(UObject *,UClass *);
static UClass PrivateStaticClass;
static void PurgeGarbage(void);
static int ResolveName(UObject * &,unsigned short const * &,int,int);
static void SafeLoadError(unsigned long,unsigned short const *,unsigned short const *,...);
void SetLinker(ULinkerLoad *,int);
void UnhashObject(int);
};

Picklelicious
22nd October 2004, 20:12
HelioS, that virtual function order looks correct to me. It matches the VMT (??_7UObject@@6B@).

I think having UObject decend from FUnknown is wrong. It makes sense that it should. The 432 headers show UObject decending from FUnknown. But if you look at UObject's constructor code, it does not call FUnknown's constructor (which it should do if it really decended from it).

Also, FUnknown's functions (QueryInterface, AddRef, Release), don't do anything. The same functions in UObject don't do anything either, yet UObject replaces those FUnknown functions (which doesn't make any sense since none of them do anything).

I think the code base changed and UObject nolonger inherits from FUnknown.

HelioS
22nd October 2004, 21:35
FUnknown is an empty class anyway so it doesn't mather if you extend it or not
UT's core didn't change since the demo and they still use FUnknown, so why change to UObject as baseclass all of a sudden :)

And yea i sorted the virtual functions with the vftable by comparing the addresses of that table against the function addresses of the virtual functions.
Only the destructor is causing some trouble

Picklelicious
22nd October 2004, 22:29
FUnknown is an empty class anyway so it doesn't mather if you extend it or not UT's core didn't change since the demo and they still use FUnknown, so why change to UObject as baseclass all of a sudden :)I have been making a tool that helps hack the UT engine. It only uses what is available in memory from a running UT game. I could not find anything in memory that indicates that UObject decends from FUnknown. I guess the question is why make UObject descend from FUnknown when there is nothing in memory that would indicate that?

FUnknown is still exported from core, but I could not find anything that actually uses it. It seems to be dead code. All the code indicates that they changed the UObject definition. But as you said, it is not going to make a difference.

And yea i sorted the virtual functions with the vftable by comparing the addresses of that table against the function addresses of the virtual functions. Only the destructor is causing some troubleI agree. It sort of sucks that they export the destructor, but then put a different function (which calls the destructor) in the VMT.

temp2
25th November 2004, 09:18
It sort of sucks that they export the destructor, but then put a different function (which calls the destructor) in the VMT.

Finally managed to get round to sorting the virtuals out. Is this behaviour with destructors normal? Cheers for the pointers Picklelicious & HelioS.

The virtuals seem to get get quite fascinating when there is multiple inheritance and re-definitions.

Arkan
25th November 2004, 09:21
GJ temp2, I need to email you some more source i guess, um So the new sdk, will have the functions fixed, that i need to add the menu?

Basic001
26th November 2004, 17:47
Still sorting through the .4 SDK, quite a bit to learn in there. Can't wait for the .5 SDK, please keep up the great work.

temp2
2nd December 2004, 11:26
HelioS, that virtual function order looks correct to me.

I've finally got there too. Lots learnt along the way. All my data is now stored in an Oracle database. How's the bonebot going Picklelicious and I hear HelioS is now selling the 6.3 Radar.


UObject
Ordinal UndecoratedName
0 public: virtual unsigned long __stdcall UObject::QueryInterface(class
FGuid const &,void * *)
1 public: virtual unsigned long __stdcall UObject::AddRef(void)
2 public: virtual unsigned long __stdcall UObject::Release(void)
4 public: virtual void __thiscall UObject::ProcessEvent(class UFunction
*,void *,void *)
5 public: virtual void __thiscall UObject::ProcessDelegate(class
FName,struct FScriptDelegate *,void *,void *)
6 public: virtual void __thiscall UObject::ProcessState(float)
7 public: virtual int __thiscall UObject::ProcessRemoteFunction(class
UFunction *,void *,struct FFrame *)
8 public: virtual void __thiscall UObject::Modify(void)
9 public: virtual void __thiscall UObject::PostLoad(void)
10 public: virtual void __thiscall UObject::Destroy(void)
11 public: virtual void __thiscall UObject::Serialize(class FArchive &)
12 public: virtual int __thiscall UObject::IsPendingKill(void)
13 public: virtual enum EGotoState __thiscall UObject::GotoState(class
FName)
14 public: virtual int __thiscall UObject::GotoLabel(class FName)
15 public: virtual void __thiscall UObject::InitExecution(void)
16 public: virtual void __thiscall UObject::ShutdownAfterError(void)
17 public: virtual void __thiscall UObject::PostEditChange(void)
18 public: virtual void __thiscall UObject::CallFunction(struct FFrame
&,void * const,class UFunction *)
19 public: virtual int __thiscall UObject::ScriptConsoleExec(unsigned
short const *,class FOutputDevice &,class UObject *)
20 public: virtual void __thiscall UObject::Register(void)
21 public: virtual void __thiscall UObject::LanguageChange(void)
22 public: virtual void __thiscall UObject::Rename(unsigned short const
*,class UObject *)
23 public: virtual void __thiscall UObject::NetDirty(class UProperty *)
24 public: virtual int __thiscall UObject::AllowGarbageCollection(void)

UCanvas : public UObject
25 public: virtual void __thiscall UCanvas::Init(class UViewport *)
26 public: virtual void __thiscall UCanvas::Update(void)
27 public: virtual void __thiscall UCanvas::DrawTile(class UMaterial
*,float,float,float,float,float,float,float,float, float,class
FPlane,class FPlane,in t)
28 public: virtual bool __thiscall UCanvas::CheckTrimX(float &,float
&,float &,float &)
29 public: virtual bool __thiscall UCanvas::CheckTrimY(float &,float
&,float &,float &)
30 public: virtual void __thiscall UCanvas::DrawIcon(class UMaterial
*,float,float,float,float,float,class FPlane,class FPlane)
31 public: virtual void __thiscall UCanvas::DrawPattern(class UMaterial
*,float,float,float,float,float,float,float,float, class FPlane,class
FPlane)
32 public: virtual void __cdecl UCanvas::WrappedStrLenf(class UFont
*,float,float,int &,int &,unsigned short const *,...)
33 public: virtual void __cdecl UCanvas::WrappedStrLenf(class UFont
*,int &,int &,unsigned short const *,...)
34 public: virtual void __cdecl UCanvas::WrappedPrintf(class UFont
*,float,float,int,unsigned short const *,...)
35 public: virtual void __cdecl UCanvas::WrappedPrintf(class UFont
*,int,unsigned short const *,...)
36 public: virtual void __thiscall UCanvas::WrapStringToArray(unsigned
short const *,class TArray<class FString> *,float,class UFont *,unsigned
short)
37 public: virtual void __thiscall UCanvas::ClippedStrLen(class UFont
*,float,float,int &,int &,unsigned short const *)
38 public: virtual void __thiscall UCanvas::ClippedPrint(class UFont
*,float,float,int,unsigned short const *)
39 public: virtual void __thiscall UCanvas::DrawTileStretched(class
UMaterial *,float,float,float,float)
40 public: virtual void __thiscall UCanvas::DrawTileScaled(class
UMaterial *,float,float,float,float)
41 public: virtual void __thiscall UCanvas::DrawTileBound(class
UMaterial *,float,float,float,float)
42 public: virtual void __thiscall UCanvas::DrawTileJustified(class
UMaterial *,float,float,float,float,unsigned char)
43 public: virtual void __thiscall UCanvas::DrawTileScaleBound(class
UMaterial *,float,float,float,float)
44 public: virtual void __cdecl UCanvas::DrawTextJustified(unsigned
char,float,float,float,float,unsigned short const *,...)
45 public: virtual void __thiscall UCanvas::SetClip(int,int,int,int)

select vft.Ordinal, fun.UndecoratedName
from ExportedFunctions exp, VFTables vft, ExportedFunctions fun
where exp.Version = 'AA 2.2.1'
and exp.UndecoratedName like '%vftable%'
and exp.Class = 'UCanvas'
and vft.Version = exp.Version
and vft.TableStartAddress = exp.Address
and exp.Version = fun.Version
and vft.VFPointer = fun.Address
and exp.Class = fun.Class
order by vft.Ordinal;

select count(*)
from vftables;

COUNT(*)
84336