Engine rendering with object manipulation in A2OA

This image has been resized. Click this bar to view the full image. The original image is sized 1900×1002.

D3D is hard.

With Battleye hook scanning D3D Endscene and Present and apparently being very liberal about deciding what is and is not a hack, I had to find some alternative to hardhooking Present. I could have made an overlay or something, but since I’m a masochist I decided instead to investigate how the Arma engine draws on the screen.

How Scripters Draw Things on the Screen

Script ESP is a thing, so it has to be possible to leverage the script system to do our drawing for us, or at least give us a clue as to what we need to manipulate to draw on the screen. Investigating script ESPs, we can see that Arma has numerous displays, and displays have controls to draw individual objects.

PHP Code:
                                disableSerialization;
((_this select 0 distance (positionCameraToWorld [0,0,0]))) cutRsc ['rscDynamicText', 'PLAIN'];
_ctrl = ((uiNamespace getvariable 'BIS_dynamicText') displayctrl 9999);
_ctrl ctrlShow true;
_ctrl ctrlEnable true;
_unit = _this select 0;
while {((((positionCameraToWorld [0,0,0]) distance _unit) < fnc_esp_distance) && (fnc_esp_state == 1))} do
{
if ((isNull _unit) || !(alive _unit)) exitWith {};
if ((fnc_esp_state == 0) || (visibleMap)) exitWith {};
_pos = (positionCameraToWorld [0,0,0]);
_posU = getPos _unit;
_dist = round(_pos distance _posU);_veh = vehicle _unit;
_posU2 = [(getPosATL _veh) select 0, (getPosATL _veh) select 1, ((getPosATL _veh) select 2) + (((boundingBox _veh) select 1) select 2) + 0.5];
_pos2D = worldToScreen _posU2;
if (count _pos2D > 0) then
{
if (_dist <= 35) then {_ctrl ctrlSetFade 0;};

if (_dist > 1000) then {_ctrl ctrlSetFade 0.85;};

_Tsize = 0.4;
_text = format [‘<t size=”%3” font=”Zeppelin33” color=”#0B80FF”>%1 (%2m)</t>’,name _unit,round _dist,_Tsize];
if (name _unit == name player) then {_text = ”};
if (_unit != _veh) then
{
_crewnames = [];
{
_crewnames = _crewnames + [name _x];
} forEach crew _veh;
_posU2 = [_posU2 select 0,_posU2 select 1,(_posU2 select 2) + 1.5];
_pos2D = worldToScreen _posU2;
_text = format [‘<t size=”%3” font=”Zeppelin33” color=”#FF5926”>%1 (%2m) %4</t>’,_crewnames,round _dist,_Tsize,typeOF _veh];
};
_ctrl ctrlSetStructuredText (parseText _text);
_ctrl ctrlSetPosition [(_pos2D select 0) – (safezoneW / 2), (_pos2D select 1), safezoneW, safezoneH];
_ctrl ctrlCommit 0;
};
sleep .01;
};
_ctrl ctrlShow false;
_ctrl ctrlEnable false;
fnc_esp_unitarray = fnc_esp_unitarray – [_unit];
};

In this code, the scripter (whoever Infistar copied it from) gets display BIS_dynamicText, and selects control ‘9999’ from the display. It then updates the control with what it should draw and where it should draw it, and enables the control. This might be confusing because the scripter uses control 9999 for everything he draws on the screen. Does this mean that a single control can contain a bunch of things to draw? Does this mean that we have just a shit ton of control 9999’s? To answer these questions you should read the Bohemia wiki page on dialogues and controls:https://community.bistudio.com/wiki/Dialog_Control

Did that answer your questions? No? That’s because the script interface is almost completely useless in determining what is actually happening behind the scenes. So we have to dig deeper. To find out what’s happening, we’re going to have to look at the actual display and control objects.Thanks, Obama.

Display and Control Objects

So how do we find a display? Luckily, the script engine comes in handy here. the findDisplay function saves a handle to the display object, which is actually a pointer. You can find the address of a display object by printing the result of findDisplay. Alternatively, you could hook findDisplay and check the contents of the return object, or just reverse findDisplay and find out where the displays are stored. Unfortunately, there’s no table of displays. There are multiple links to displays, and some displays are in a linked list to other displays. It’s a huge fucking mess. It doesn’t help that not all display objects are identical – like Soldier and Vehicle, they have inheritance to the same base classes, but far enough into the class they are totally different objects.

That being said, there are a few displays we can find in the same place every time.

PHP Code:
class World
{
public:
char _0x0000[8];
InGameUI* inGameUI; //0x0008
char _0x000C[16];
isplayMain* displayMain; //0x001C
char _0x0020[1496];
DisplayMainMap* displayMainMap; //0x05F8

DisplayMain is the main menu, DisplayMainMap is the map display. Inside InGameUI we have access to a few more displays…

PHP Code:
class InGameUI
{
public:
char _0x0000[24];
__int32 showHUD; //0x0018
char _0x001C[8];
D3DXVECTOR3 crossHairCoords;
float rangeToReticleTarget; //0x0030
char _0x0034[52];
D3DXVECTOR3 crosshairObjectCoords;
char _0x0074[1316];
__int32 InGameUITimer; //0x0598
char _0x059C[28];
AutoArray<DisplayContainer> unitInfoDisplays;
char _0x05C4[12];
DisplayHint* displayHint; //0x05D0
DisplayHint* displayTaskHint; //0x05D4
__int32 hintTimer; //0x05D8
char _0x05DC[8];
ArmaString* hintSound; //0x05E4

So inside InGameUI, we have access to the DisplayHint and DisplayTaskHint displays. Obviously, DisplayHint is what draws hints on the screen, and DisplayTaskHint puts those little tasks hints up. UnitInfoDisplays is a slightly different animal – UnitInfoDisplay draws your ammo and stuff on the screen. When you’re in a vehicle, it draws your damage and fuel levels. It’s in an autoarray of containers. Those containers look like this:

PHP Code:
class DisplayContainer
{
public:
ArmaString* displayName; //0x0000
DisplayUnitInfo* subDisplay; //0x0004
__int32 displayTimer; //0x0008
};//Size=0x000C

So we have the name of the display, a pointer to the display, and a timer. That timer determines whether or not the display is drawn. If you’ve ever noticed, your ammo count fades off of the screen if you haven’t fired or switched weapon types in a few seconds – that timer is what controls that. If it is X less than the inGameUI timer in the InGameUI class, your shit starts to fade and go away.

By the way, the number of displays in this auto array is controlled by a value in your CfgVehicle, though I’ve never seen a vehicle with more than one display.

So, let’s have a look at the DisplayUnitInfo display:

PHP Code:
class DisplayUnitInfo
{
public:
char _0x0000[8];
Link<DisplayUnitInfo>* link; //0x0008
__int32 idd; //0x000C
Link<void*>* link2; //0x0010
ArmaString* displayName; //0x0014
char _0x0018[56];
AutoArray<TextContainerControl*> controlArray;
char _0x005C[904];
TextContainerControl* ca_weapon; //0x03E4
TextContainerControl* ca_ammo; //0x03E8
char _0x03EC[4];
TextContainerControl* ca_mode; //0x03F0
char _0x03F4[108];
}

Now we’re cookin! Here we have an array of controls, and direct pointers to the three controls that typically make up your weapon display: the weapon name, how much ammo you have, and the fire mode. We also have those link objects, which look like this:

PHP Code:
template <class C>
class Link
{
public:
void* vtable;
__int32 refCount; //0x0004
C* thisPtr; //0x0008

Remember how I told you displays are in a linked list? There’s a link to the object, a link to the previous object in the list, and a third link to the next object in the list.

So we’re at a display that we could draw on. We could either only draw when the ammo counter is up, or manipulate the timer to ensure that the ammo timer is ALWAYS displayed, and so would the things we draw be. Now what? Well, no thanks to Bohemia Wiki or the script engine, we now know that displays just contain arrays of controls mostly. In this case, the display has pointers to controls it expects to have, but this is not always the case as you will see if you explore other displays.

Now what? Well let’s play with some controls. Now, there are a bunch of controls. Just like soldiers/vehicles, they share the same base classes but are very different near the bottom of the class. If you wanted to play with multiple controls and draw buttons and boxes and things, it would probably behoove you to emulate the inheritance structure of the controls that you want to manipulate in your classes. In this case, we’re going to be playing with the static text control:

PHP Code:
class TextContainerControl
{
public:
char _0x0000[4];
__int32 refCount; //0x0004
Link* link; //0x0008
char _0x000C[4];
Link* link2; //0x0010
__int32 idc; //0x0014
armaString* controlName; //0x0018
__int8 drawControl; //0x001C
BYTE enabled; //0x001D
BYTE keyboardSelected; //0x001E
char _0x001F[1];
BYTE mouseSelected; //0x0020
char _0x0021[3];
BYTE shadow; //0x0024
BYTE shadowColor; //0x0025
char _0x0026[2];
DWORD N0C9B5B23; //0x0028
char _0x002C[4];
armaString* mouseoverText; //0x0030
char _0x0034[756];
__int32 controlType; //0x0328
__int32 alignment; //0x032C
float xAxis; //0x0330
float yAxis; //0x0334
float width; //0x0338
float height; //0x033C
float textScale; //0x0340
float overallScale; //0x0344
float opacity; //0x0348
char _0x034C[124];
DWORD vtable3; //0x03C8
armaString* text; //0x03CC
__int32 colorBackground; //0x03D0
__int32 colorText; //0x03D4
font* font; //0x03D8
float sizeEx; //0x03DC .034
char _0x03E0[4];
__int32 fixedWidth; //0x03E4
__int32 loops; //0x03E8
char _0x03EC[40];
float lineSpacing; //0x0414
};//Size=0x0418

By messing around with the values we can see what effect they have

Adding Our Own Controls
So now what? We have all the classes we need to start making our own controls and drawing things on the screen. So…let’s do that I guess?

Building your Control

Oh man, what the fuck is all this shit? Well, for drawing text, you need to know:

  • idc – the control ID
  • controlName – the name of the control
  • drawControl – determines if the control is drawn (duh)
  • shadow – determines if the text has a drop shadow (1), an outline (2), or nothing (0)
  • Alignment – 0 is right aligned, 1 is centered, 2 is left aligned. This is alignment in the width AND height of the control display area
  • xAxis and yAxis – where the top left of the control is placed on the screen
  • width and height – the size of the control box
  • text – this is the text that is actually drawn in the control
  • sizeEx – the size, in Arma’s stupid relative screen size garbage value, of the height of the font.
  • font – a pointer to a font object for the font you want to use. You can copy from an existing control, or look to the script engine for help

You don’t have to worry about the IDC or name, unless you want to use them to identify controls of certain objects (that way you can update an object’s control when you want to redraw it). Really all you have to do is set the text and position if you’re copying from an existing control or using a pre-made default one. Speaking of position…

Positioning your Control
At this point you should be able to easily make a control to draw WHAT you want. But what about WHERE you want it? You can’t just feed it a screen position in pixels and have it draw there – no. Arma uses this safezone system, where the screen X and Y are two floats where 0.5 is the middle of the screen and the edges are different depending on your aspect ratio.

https://community.bistudio.com/wiki/SafeZone

So that’s cool. You’re stuck figuring out the safe zone to position your menu items, and then either doing a safezone W2S or converting pixel coordinates to safezone coordinates for your entity drawing. That sounds fun as shit! Luckily, you can easily calculate your safezone.

Code:
class D3DClass
{
public:
char _0x0000[136];
	float x1; //0x0088 
	float y2; //0x008C 
	float x2; //0x0090 
	float y2; //0x0094 
char _0x0098[636];
	__int32 windowWidth; //0x0314 
	__int32 windowHeight; //0x0318 
char _0x031C[1316];

float getSafeZoneW() {
float ratio = 1 / (x2 - x1);
return (1 + 2 * x1 *ratio);
}

float getSafeZoneH() {
float ratio = 1 / (y2 - y1);
return (1 + 2 * y1 *ratio);
}


};//Size=0x0840

Where D3DClass = *DF514C.

So with the width and height of the safe zones, you can easily calculate the safe zone positions of the borders of the screen so you can draw your menu. What about entities in the world?

Well, fatboy long ago developed a world to screen for the Arma series: transformation

That converts world to screen coordinates, while we need SafeZone/UI coordinates. All you have to do is:

Code:
safezoneX = (screenX - d3dObject.x1) / (d3dobject.x2 - d3dObject.x1)

Too easy.

And that’s all there is to it. Create some control objects, set them up, and drop them in a display. To change your control, just find it and change its values around a little bit. You can dump them all in DisplayUnitInfo and have your ESP on the screen whenever the ammo count is on the screen. #YOLOswag

Notes

Script based anti-hacks can find your controls by getting the display, then getting a control by its IDC. However, you CANNOT retrieve a handle to a control object that has an IDC of -1, so if you make all your controls have IDC -1 the anti-hack can’t find them.

The ‘center’ alignment centers your control on the X AND Y axis of the control drawing area. Since I have no idea how to get the width of a string in terms of UI space, I’ve had to make my control boxes really big, use center alignment, and subtract half of the width and height of the control from the position to center text.

sizeEx is the height of the font in terms of UI space. This means that a control’s position + sizeEx will put you perfectly below the font of that control, making it easy to ‘stack’ text controls on top of one another.

Theoretically, this could be done from an external process, so you could have internal ESP from an external hack. It’s a fun thought!

There are controls for all sorts of stuff, including formatted text, transparent boxes, buttons, you name it. You could easily reverse those structures to do much more very much cooler drawing, cause plain text is a little lame I know.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s