I've done some thinking (not much) and decided to dig around with OllyDbg to try to find out where XLive checks for the debugger. The first thing I decided to do was the simplest I could think of, search for is the intermodular call kernel32.IsDebuggerPresent.
Looking around in olly I found 2 locations where this was being referenced, and decided to try exiting the function from the very beginning. Although, first, I did try just returning false for IsDebuggerPresent by setting byte ptr [eax+2] to 0 but shortly after I found that.. as the old saying goes.. "there's more than one way to skin a cat". The best way is just to exit the function before it executes, but even this method may cause problems as you will soon find out.
For starters, this was found and tested with xlive.dll v3.0.19 (15,308,424 bytes). I haven't had the chance to see if these byte patterns are consistent with previous versions though. The first 2 locations are easy enough:
Byte Pattern #1: 6A 01 E8 80 8C 1B 00 59 6A 00
Distance: -0xC0
Static Address: xlive.dll+45EE9D
Replacement Bytes: 8B FF -> C3 90
Byte Pattern #2: 33 C5 89 45 FC 53 56 8B 75 08 33 DB 57 89 9D CC F9 FF FF 89 9D C0 F9 FF FF
Distance: -0x10
Static Address: xlive.dll+1439C1
Replacement Bytes: 8B FF 55 -> C2 08 00
Now you might be saying, I thought there were only 2 locations to begin with.. how can the first 2 be easier than any others? Well, if you patch these locations and try attaching the debugger you will soon find that there's yet another location that needs to be patched. Since there isn't another reference to kernel32.IsDebuggerPresent listed in with the other intermodular calls, we need to resort to drastic measures. The thing I did in this situation is place a breakpoint inside the IsDebuggerPresent function (located at kernel32.dll+0x13133 for WinXP x86 sp3), then hit F7 until it returns to the calling function. When you do this you will see that it's not being called directly, but rather by using GetProcAddress then call eax which is why there wasn't anymore listings. So we do the same here as we did with the others:
Byte Pattern #3: E8 15 53 01 00 2D D1 07 4E 58 F7 D8 1B C0 40
Distance: -0x17
Static Address: xlive.dll+14747C
Replacement Bytes: 8B FF -> C3 90
After you enable all 3 patched locations you should be able to attach the debugger, see what writes/accesses any address and then some. There are some drawbacks though, mainly with the 3rd patch location. Patching this location will almost definitely disable GFWL completely, which means no loading or saving or anything else. This also means that it can cause problems for some games so it's best to only enable these when you're ready to debug, to avoid any unnecessary problems.
Another drawback is that these aren't always 100% by themselves, especially when dealing with games that have launchers. Sometimes the game's launcher will also have some debug protection implemented, which means you will have to find and patch these locations as well, as with Resident Evil 5 and Star Wars The Clone Wars: Republic Heroes.
I tested these with Red Faction: Guerrilla, Resident Evil 5, and Star Wars Republic Heroes, but RE5 and SWRH both have launchers that also contain anti-debug techniques, RFG allows you to launch the game without the launcher , so a little extra work is needed for those to allow debugging. Here's a very simple walkthough on how to find the IsDebuggerPresent locations using OllyDbg (you can find a nice article on anti-debugging techniques here):
1.) Open the game exe or launcher exe.
2.) Right click anywhere on the CPU disassembler window, then goto Search for->All intermodular calls.
- This will open a new window which contains all imported functions (APIs) used by the exe. You can sort them alphabetically by proc name (not module name) by clicking the associated column header.
3.) Locate kernel32.IsDebuggerPresent and double click on a location entry to follow it in the disassembler.
Easy, right? From here all you need to do is find the beginning of the function and then just RETN or whatever the return call is for the function in question. You can use MHS to select the entire function then find the end to see what type of RETN it uses.
Any questions, comments, corrections, suggestions are all welcome. Probably nobody will give me credit when due so all y'all bitchez can rot in the place you find most uncomfortable!!! If you do give credit, then apparently I'm not talking to you.