Category Archives: Watch Dogs

Watch Dogs Script Hook goes GitHub

I’ve decided to put my Watch Dogs Script Hook on GitHub because I still receive questions regarding the game, although I haven’t touched neither the game nor the code for ages. So here it is for you to play around:

Please note that it does not work with the latest version of the game and should be considered an educational resource for game reversing/hacking. Also note that the code is very hacky and ugly and has major design flaws. But it works! ūüėõ

Watch Dogs Lua Engine Hook #2

I’ve continued working on my script hook for Watch Dogs and now also added support for GetAsyncKeyState in lua. Also, as it can be very handy, I allow lua scripts to run in a loop now, since each is spawned in a new thread. This allows code like this:

while true do
-- Change time when C is down
local result = wdHook.GetAsyncKeyState(67);
if (result == 1) then
test:SetScriptedTimeOfDay(18, 00);


Quite useful, right?

D3D11 hook

In addition, I got a basic D3D11 hook working, so I’m now able to draw on the rendered image (upper left corner):


I need to move this into a lua callback to add drawing support for lua too, but that shouldn’t be too hard to implement. Once I got that working I’ll do some final tests and then hope to release my hook for all the scripters out there! ūüôā

For those of you trying to get ad3d11 hook to work, keep in mind you need to save the jmp Steam places in the function, for instance at D3D11Present. I do this by reading the target address of the Steam call, adding the current location (RIP) to get the full address and then executing something like this:

mov rax, addr
jmp rax

This will keep the Steam overlay working and you can still use your own hooked function by executing it right before.

Furthermore, if you have trouble detouring D3D11DrawIndexed, this might help you (reversed to C++ from original WD implementation):

DWORD64 dwContext = (DWORD64)pContext + 0x0009C08;
D3D11DrawIndexedHook dwCallTarget = (D3D11DrawIndexedHook)*(DWORD64*)(pContext + 0x8D);
return dwCallTarget((ID3D11DeviceContext*)dwContext, IndexCount, StartIndexLocation, BaseVertexLocation);

Happy coding!

Watch Dogs Lua Engine Hook

Today I finished my work on a hook for the Watch Dogs lua engine. It can now load lua script files into the game and execute them and also gives access to all lua scripting functions available ingame, so spawning vehicles, changing time of day etc. is now possible. A short scripting example:

local test = CDynamicEnvironmentManager_GetInstance();
test:SetScriptedTimeOfDay(09, 23);

This simple script changes the time to 9:23. It can be saved as anything.lua and put into /scripts/ folder and will then be loaded by my hook at startup. You can also reload it at any time during gameplay so testing new stuff is pretty easy. I might release the hook to the public soon, depending on how testing goes.

Hook internas

I created a proxy of dinput8.dll to get loaded into the process and then load up my custom C++ dll. The injection works by using the functions loadbuffer and pcall from lua which reside inside Disrupt_b64.dll. Once you found them, you can manually call them and load your own scripts into the game and have them processed like normal game scripts. Protoypes:

int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, const char *name);
int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);

All you gotta do is find the lua state in the game and that’s it! You can then call those two functions to load your own script data and execute it while playing.

Expect more soon.

An example screen:


Watch Dogs: First RE impressions


so yesterday I started messing around with Watch Dogs and its Disrupt engine. The main code is located in Disrupt_b64.dll, but it’s packed. To unpack, simply attach IDA to the process and dump the loader segments. The following information is based on my base address: 000007FB46240000

Lua base functions

Watch Dogs makes heavy use of lua, almost all things internally are scripted using it. The lua base functions can be found at 000007FB4906FEA0. You’ll find something along these lines:

.rdata:000007FB4906FEA0 baseFuncs       dq offset aAssert       ; DATA XREF: sub_7FB47A528C0+27o
.rdata:000007FB4906FEA0                                         ; "assert"
.rdata:000007FB4906FEA8                 dq offset luaB_assert
.rdata:000007FB4906FEB0                 dq offset aCollectgarbage ; "collectgarbage"
.rdata:000007FB4906FEB8                 dq offset luaB_collectgarbage
.rdata:000007FB4906FEC0                 dq offset aDofile       ; "dofile"
.rdata:000007FB4906FEC8                 dq offset luaB_dofile
.rdata:000007FB4906FED0                 dq offset aError_1      ; "error"
.rdata:000007FB4906FED8                 dq offset luaB_error
.rdata:000007FB4906FEE0                 dq offset aGcinfo       ; "gcinfo"
.rdata:000007FB4906FEE8                 dq offset luaB_gcinfo

These are the core lua functions and it’s useful to name them and also have a look at how they work (source can be found here to help understanding them

Lua scripting functions

The lua scripting functions start with GetBaseHealth at 000007FB48E7F300 and look like this:

.rdata:000007FB48E7F300 off_7FB48E7F300 dq offset aGetbasehealth
.rdata:000007FB48E7F300                                         ; DATA XREF: .text:000007FB46632DE0o
.rdata:000007FB48E7F300                                         ; .text:000007FB46638130o
.rdata:000007FB48E7F300                                         ; start of lua scripting functions
.rdata:000007FB48E7F308                 dq offset lua_GetBaseHealth
.rdata:000007FB48E7F310                 dq offset aGetcurrentheal ; "GetCurrentHealth"
.rdata:000007FB48E7F318                 dq offset lua_GetCurrentHealth
.rdata:000007FB48E7F320                 dq offset aIsalive      ; "IsAlive"
.rdata:000007FB48E7F328                 dq offset lua_IsAlive
.rdata:000007FB48E7F330                 dq offset aIsdead       ; "IsDead"
.rdata:000007FB48E7F338                 dq offset lua_IsDead

Mapping the functions

This might be just plain data for you in IDA due to the dump, but my following IDC script should help you finding all offsets and assigning all function names:

auto base = 0xSTART;
auto end = 0xEND;
auto c = (end - base) / 8;
auto i;
auto adr;
auto name;
auto ref;
auto lastWasString;
for (i=0;i<c;i++)
        adr = base + i*8;
        MakeQword(base + i*8);
        if (GetSegmentAttr(adr, SEGATTR_TYPE) != 3)
                SetSegmentType(base + i*8, 3);

        // Check if string
        Message("Checking %x", adr);
        ref = Qword(adr);
        Message(" -- ref: %x", ref);
        auto type;
        type = GetStringType(ref);
        Message(" -- stringType: %x", type);
        if (type == 0)
            Message("--> IsString");
            auto string;
            string = GetString(ref, -1, 0);
            Message(" -- %s", string);
            lastWasString = 1;
            name = string;
            lastWasString = 0;
        // If no string, try to make code at target location
        if (!lastWasString)
            auto result;
            // If no code
            if (GetSegmentAttr(ref, SEGATTR_TYPE) != 2)
                result = MakeCode(ref);
                Message("-- MakeCode: %x", result);
            // Try making function
            result = MakeFunction(ref, BADADDR);
            Message("-- MakeFunction: %x", result);
            // Rename
            auto tempName = "lua_" + name;            
            result = MakeName(ref, tempName);
            Message("-- MakeName: %x", result);

Just edit start/end at the top to match it to your offsets and let it run. This may take quite a while and will also toggle some IDA reanalysis afterwards, because it creates code out of data segments. But as a result, you get some nice looking lua functions properly named.

Lua functions dump

For those of you interested, here are some functions dumped from memory with their address: