Steam GameOverlayUI hooking and microsoft rage!

Alright, before I start this post I’m going to rant about something. Microsoft needs to cut the bullshit and implement a global, system-wide rendering method for overlays. Fraps, Steam, XFire, Raptr, Origin, Teamspeak and a ton of other gaming related applications have to hook into games, as it stands, to render what they want. This is unacceptable. Steam’s GameOverlayUI overlay currently has hooks on DirectDraw, OpenGL, DirectX 8, 9, 10, 11 (and it hooks various methods of initializing these interfaces, so CreateDXGIFactory, CreateDXGIFactory1, Direct3DCreate9, Direct3DCreate9Ex, DirectDrawCreate, DirectDrawCreateEx)… this is… insane. Surely, somebody must realize this besides myself. I admire the developer of the overlay (assuming it’s still just one guy) and I’ve actually mailed him before telling him it’s very neat, but nobody should have to do this. Just talking about it is getting me angrier. Microsoft, please solve this problem. You can even make a function to retrieve all the overlays so cheaters aren’t a problem, or something, I don’t know but please do something. (Yes, I’m fully aware nobody from microsoft will read this, I’ll send an email bitching at them that nobody will read later)

Moving on, I have reversed the GameOverlayUI again as I have done in the past, I’ve released an update and I wanted to post about it.

with Steam's GameOverlayUI

Rendering in Payday with GameOverlayUI

Some people have asked how I have accomplished this and while it’s a little hard to explain I think I’ll try anyway. Steam’s GameOverlayUI.exe loads several modules:
1. bin/gameoverlayui.dll
2. bin/vgui2_s.dll

First thing you need to understand about the GameOverlayUI is that all of it’s interfaces are in VGUI format, that is, drawing text, filling rects or whatever, they all use IPanel, ISurface and etc from the Source SDK. They just override the functions to do what they want. Example would be here (From vgui2_s.dll):

 ASM |  copy code |? 
01
.rdata:3F272CBC   SerializedSurface dd offset sub_3F21F6B0
02
.rdata:3F272CBC                                           ; DATA XREF: CreateSerializedSurface+2Do
03
.rdata:3F272CBC                                           ; CreateSerializedSurface_002+Do
04
.rdata:3F272CC0                   dd offset sub_3F21A4D0
05
.rdata:3F272CC4                   dd offset sub_3F217F10
06
.rdata:3F272CC8                   dd offset sub_3F21A3D0
07
.rdata:3F272CCC                   dd offset sub_3F21A4A0
08
.rdata:3F272CD0                   dd offset sub_3F218F50
09
.rdata:3F272CD4                   dd offset sub_3F215FE0
10
.rdata:3F272CD8                   dd offset sub_3F21A3F0
11
.rdata:3F272CDC                   dd offset sub_3F21A4E0
12
.rdata:3F272CE0                   dd offset SerializedSurface__PushMakeCurrent
13
.rdata:3F272CE4                   dd offset SerializedSurface__PopMakeCurrent
14
.rdata:3F272CE8                   dd offset CBaseSurface__DrawSetColor_RGBA
15
.rdata:3F272CEC                   dd offset CBaseSurface__DrawSetColor_Color
16
.rdata:3F272CF0                   dd offset SerializedSurface__DrawFilledRect
17
.rdata:3F272CF4                   dd offset CBaseSurface__DrawFilledRectArray
18
.rdata:3F272CF8                   dd offset CBaseSurface__DrawOutlinedRect
19
.rdata:3F272CFC                   dd offset SerializedSurface__DrawLine
20
.rdata:3F272D00                   dd offset SerializedSurface__DrawPolyLine
21
.rdata:3F272D04                   dd offset CBaseSurface__DrawSetTextFont
22
.rdata:3F272D08                   dd offset CBaseSurface__DrawSetTextColor_RGBA
23
.rdata:3F272D0C                   dd offset CBaseSurface__DrawSetTextColor_Color
24
.rdata:3F272D10                   dd offset CBaseSurface__DrawSetTextPos
25
.rdata:3F272D14                   dd offset CBaseSurface__DrawGetTextPos
26
.rdata:3F272D18                   dd offset SerializedSurface__DrawPrintText
27
.rdata:3F272D1C                   dd offset CBaseSurface__DrawUnicodeChar
28
.rdata:3F272D20                   dd offset sub_3F2162D0

The gameoverlayui.dll is essentially all of the code for GameOverlayUI.exe, seriously, the exe itself does basically nothing at all. In that module it will initialize interfaces from vgui2_s.dll. If you want to update my hook, that’s how you do it. Find the SerializedSurface (It’s easy, search text)

 C++ |  copy code |? 
1
int __stdcall SerializedSurface__DrawOutlinedCircle(int a1, int a2, int a3, int a4)
2
{
3
  return Log("SerializedSurface::DrawOutlinedCircle() not yet implemented\n");
4
}

You can usually derive the entire ISurface class with this or at least the relevant parts. IPanel and ISurface are all you need to render.

Moving on, they did something weird in newer GameOverlayUI… there’s a new interface and you can not grab ISurface directly from it’s interface name. You have to first use a class I called “ISetup”

 C++ |  copy code |? 
1
class ISetup
2
{
3
public:
4
	virtual void Unknown01() = 0;
5
	virtual void Unknown02() = 0;
6
	virtual void Unknown03() = 0;
7
	virtual void Unknown04() = 0;
8
	virtual ISurface* CreateSurfaceInterface(char* Version) = 0;
9
};

 C++ |  copy code |? 
01
	while(g_pSetup == NULL)
02
	{
03
		g_pSetup = (ISetup*)VGUIInterface("VGUI_Setup001", NULL);
04
 
05
		Sleep(100);
06
	}
07
 
08
	gApp.AddToLogFileA("hook.log", "g_pSetup = 0x%X", g_pSetup);
09
 
10
	while(g_pSerializedSurface == NULL)
11
	{
12
		g_pSerializedSurface = g_pSetup->CreateSurfaceInterface("VGUI_Surface032");
13
 
14
		Sleep(100);
15
	}
16
 
17
	gApp.AddToLogFileA("hook.log", "g_pSerializedSurface = 0x%X", g_pSerializedSurface);

Anyway, after you have reversed the ISurface interface and have accessed it, you need to hook IPanel next and document a function called “GetName” (so that you can draw on the UI panel, and not all panels), luckily, it has hardly changed from the Source SDK’s version.

 ASM |  copy code |? 
01
.rdata:3F27756C   CPanel          dd offset sub_3F2376F0  ; DATA XREF: .data:off_3F28C9B8o
02
.rdata:3F277570                   dd offset Init
03
.rdata:3F277574                   dd offset SetPos
04
.rdata:3F277578                   dd offset GetPos
05
.rdata:3F27757C                   dd offset SetSize
06
.rdata:3F277580                   dd offset GetSize
07
.rdata:3F277584                   dd offset GetMinimumSize
08
.rdata:3F277588                   dd offset SetMinimumSize
09
.rdata:3F27758C                   dd offset GET_UNK_002
10
.rdata:3F277590                   dd offset SetZPos
11
.rdata:3F277594                   dd offset GetZPos
12
.rdata:3F277598                   dd offset GetAbsPos
13
.rdata:3F27759C                   dd offset GetClipRect
14
.rdata:3F2775A0                   dd offset SetInset
15
.rdata:3F2775A4                   dd offset GetInset
16
.rdata:3F2775A8                   dd offset SetVisible
17
.rdata:3F2775AC                   dd offset IsVisible
18
.rdata:3F2775B0                   dd offset SetParent
19
.rdata:3F2775B4                   dd offset GetChildCount
20
.rdata:3F2775B8                   dd offset GetChild
21
.rdata:3F2775BC                   dd offset GetParent
22
.rdata:3F2775C0                   dd offset sub_3F237210
23
.rdata:3F2775C4                   dd offset MoveToFront
24
.rdata:3F2775C8                   dd offset MoveToBack
25
.rdata:3F2775CC                   dd offset HasParent
26
.rdata:3F2775D0                   dd offset IsPopup
27
.rdata:3F2775D4                   dd offset SetPopup
28
.rdata:3F2775D8                   dd offset IsFullyVisible
29
.rdata:3F2775DC                   dd offset GetScheme
30
.rdata:3F2775E0                   dd offset IsProportional
31
.rdata:3F2775E4                   dd offset IsAutoDeleteSet
32
.rdata:3F2775E8                   dd offset DeletePanel
33
.rdata:3F2775EC                   dd offset SetKeyBoardInputEnabled
34
.rdata:3F2775F0                   dd offset SetMouseInputEnabled
35
.rdata:3F2775F4                   dd offset IsKeyBoardInputEnabled
36
.rdata:3F2775F8                   dd offset IsMouseInputEnabled
37
.rdata:3F2775FC                   dd offset Solve
38
.rdata:3F277600                   dd offset GetName
39
.rdata:3F277604                   dd offset GetClassName
40
.rdata:3F277608                   dd offset SendMessage
41
.rdata:3F27760C                   dd offset Think
42
.rdata:3F277610                   dd offset PerformApplySchemeSettings
43
.rdata:3F277614                   dd offset PaintTraverse
44
.rdata:3F277618                   dd offset sub_3F237410
45
.rdata:3F27761C                   dd offset sub_3F237430
46
.rdata:3F277620                   dd offset sub_3F237460
47
.rdata:3F277624                   dd offset sub_3F237490
48
.rdata:3F277628                   dd offset sub_3F2374B0
49
.rdata:3F27762C                   dd offset sub_3F2374E0
50
.rdata:3F277630                   dd offset sub_3F237510
51
.rdata:3F277634                   dd offset sub_3F237540
52
.rdata:3F277638                   dd offset sub_3F237570
53
.rdata:3F27763C                   dd offset sub_3F2375A0
54
.rdata:3F277640                   dd offset sub_3F2375D0
55
.rdata:3F277644                   dd offset sub_3F2375F0
56
.rdata:3F277648                   dd offset sub_3F2372C0
57
.rdata:3F27764C                   dd offset sub_3F2372D0
58
.rdata:3F277650                   dd offset sub_3F237610
59
.rdata:3F277654                   dd offset sub_3F2371A0
60
.rdata:3F277658                   dd offset sub_3F237170
61
.rdata:3F27765C                   dd offset sub_3F2376D0
62
.rdata:3F277660                   dd offset sub_3F2376E0
63
.rdata:3F277664                   dd offset sub_3F236FB0
64
.rdata:3F277668                   dd offset sub_3F237650

Once again finding this class in vgui2_s.dll is fairly easy:

 ASM |  copy code |? 
1
.text:3F26E560   sub_3F26E560    proc near               ; DATA XREF: .rdata:3F26F6FCo
2
.text:3F26E560                   push    offset aVgui_panel010 ; "VGUI_Panel010"
3
.text:3F26E565                   push    offset PanelGet
4
.text:3F26E56A                   mov     ecx, offset unk_3F290DA0
5
.text:3F26E56F                   call    AddInterface
6
.text:3F26E574                   retn
7
.text:3F26E574   sub_3F26E560    endp

 ASM |  copy code |? 
1
.text:3F236F80   PanelGet        proc near               ; DATA XREF: sub_3F26E560+5o
2
.text:3F236F80                   mov     eax, offset CPanel_Ptr
3
.text:3F236F85                   retn
4
.text:3F236F85   PanelGet        endp

 ASM |  copy code |? 
1
.data:3F28C9B8   CPanel_Ptr      dd offset CPanel

And you’re there, it’s up to you beyond that point to figure out where everything belongs.

Time for the final product!

 C++ |  copy code |? 
01
void __fastcall new_PaintTraverse(IPanel* This, void* _EDX, vgui::VPANEL vguiPanel, bool forceRepaint, bool allowForce)
02
{
03
	pPaintTraverse(This, vguiPanel, forceRepaint, allowForce);
04
 
05
	if(!_stricmp(This->GetName(vguiPanel), "BaseGameOverlayUIPanel"))
06
	{
07
		DrawOverlayText(g_pSerializedSurface, 10, 10, 255, 0, 0, 255, "STRING ONE");
08
		DrawOverlayText(g_pSerializedSurface, 10, 24, 255, 0, 0, 255, "STRING TWO", 3);
09
		DrawOverlayText(g_pSerializedSurface, 10, 38, 255, 0, 0, 255, "STRING THREE", 11);
10
 
11
		FillRGBA(g_pSerializedSurface, 10, 50, 10, 10, 255, 0, 0, 255);
12
 
13
		OutlineRGBA(g_pSerializedSurface, 10, 100, 10, 10, 255, 0, 0, 255);
14
	}
15
}

That’s all, I hope you enjoyed reading it.

You can download the GameOverlayUI hook here:

Download381 downloads

5 comments

  1. O my god. Super-B fantastic. Thats what I was searching.
    Is it possible to use GameOverlayUI and your hook for other games?

  2. Has tested on Dota2. vgui2_s.dll is not loaded into process memory of this game. vgui2_s.dll doesn’t exist in game’s bin directory.

    vgui2.dll exports the same named “CreateInterface” function and is loaded by the game, but it seems that CreateInterface of vgui2.dll cannot find any interface with name “VGUI_Setup001″:
    g_pSetup = (ISetup*)VGUIInterface(“VGUI_Setup001″, NULL);

  3. Read description of downloadable attachment. I should inject into GameOverlayUI.exe, not dota.exe. Anyway it is in the post, sorry for that dude.

    vgui2_s.dll is loaded into GameOverlayUI.exe, CreateInterface(VGUIInterface) finds “VGUI_Setup001″,but next code is not working

    g_pSerializedSurface = g_pSetup->CreateSurfaceInterface(“VGUI_Surface032″);

    g_pSetup->CreateSurfaceInterface always return NULL. Any updates?

  4. sirmabus says:

    As someone who has been doing either tech support and, or, programming on MS systems since the 80′s I can relate that Microsoft is really weird and annoying about some things.
    Like as if they are the be-all/end-all “experts”, their users are dumb and stupid, thus they decided to dictate how, when, and where you must do things (often archaically).
    Plus other things like they defer vital bug fixes to the “next version” to get you to needlessly buy the latest versions, etc.

    If anyone recalls besides me, “Geoworks” was a superior actually working system (fast back in the day even on a 80286!), and the openness of Linux systems is preferable. It’s too bad things didn’t go more in these direction back in the 80s and, or 90s..