View Full Version : Hooking a member function from an injected DLL?
Shakkan
March 12th, 2008, 22:06
Hi everyone,
First post here.

I've been reading/learning about reversing and assembly in the past few weeks and I'm quite thrilled. However, I came across a problem that I hope some of you gurus can help me with.
I am trying to hook a member function in a game. Once my hook function is called, I want to call the original back asap. The sole purpose of that hook is to monitor calls to that method. No cheating/hacking. :|
My problem relies on the fact that member functions are called with the _thiscall_ calling convention. That means, for MSVC, that parameters are passed from right-to-left (like _cdecl_ and _stdcall_) but ALSO that _this_ is passed to the ECX register. That means that both my hook function and my function pointer to the original method must use the _thiscall_ calling convention.
There's a sample (named 'member.cpp') in Microsoft Detours library that explains how to do such a thing. The catch is that everything in their sample is in the same source code so it's easy for them to initialize a member function pointer to the target method since they have access to the code, I don't.
All I have access to is the address of the method. I know it's not virtual since it's not called from a vtable.
I guess that my main question would be: how can I have a member function pointer point to an arbitrary address? (or how to have function ptr use _thiscall
Go there: http://pastebin.com/m6faac073 to see Microsoft Detours member function hooking sample. At line 68, they initialize the Real_Target member function pointer to &CMember::Target. Well, anyone hooking from an injected DLL will NOT have access to that code (CMember::Target) but only the address of CMember::Target (like I have, 0x005C5600 for example).
I just want to mention that I am able to inject myself, and I am able to hook myself to the method. I'm just not able to _properly_ call the original method back (no __thiscall == no more _this in ECX etc.) access violation ensues once original method wants to write a member...
I hope my problem is clear and I hope that this future discussion can help others.
Thanks in advance everyone!
disavowed
March 14th, 2008, 15:37
Quote:
[Originally Posted by Shakkan;73299]I guess that my main question would be: how can I have a member function pointer point to an arbitrary address? |
Can't you just cast the address to the member function pointer type? Like "FARPROC pFunction = (FARPROC)0x0041ABCD"?
Shakkan
March 15th, 2008, 00:14
You can do so with a function, not with a method. Anyhow, I found a way to do the hook, by converting the __thiscall method to a __stdcall hook function (pushing ECX to the stack).
For further details, see DetourClassFunc from Azorbix on Game Deception. Great work.
Now my problem lies with anti-cheating software PunkBuster even though I don't want to cheat. I just want to be notified of a certain method call but I can't alter the code at all. SEH could work but apparently, SafeDisc uses the debug registers.
...still looking for a way. I'm sure there is, I just need to learn more.
Anyone has an idea? How to be notified of a call in a certain module without altering any of its code besides SEH and hardware breakpoints?
Thank you.
disavowed
March 15th, 2008, 04:40
memory breakpoints (setting the pages to page_no_access or page_guard) and seh/veh to catch the exceptions. but it's not very performant.
Shakkan
March 15th, 2008, 09:30
And can you set a PAGE_GUARD on only a few bytes of the code segment? (i.e. not 4096)
Thank you for the suggestion.
Admiral
March 16th, 2008, 15:37
I'm afraid guarded access necessarily spans the entire page. Commonly, arbitrary granularity is emulated by resetting the guard each time it fires, transparently resuming whenever the hit is out of range. Of course, this doesn't come without a performance penalty, and it can become unworkable if a lot of activity occurs in the surrounding area, which is likely to be the case for executable code.
A better alternative would be to plant an INT3 at the function's first instruction and use a vectored exception handler to take things from there. This is a great way of efficiently halting the program when the function fires, but resuming execution is a bit of a pain.
Are you sure SafeDisc is using all the debug registers? You only need one for your purposes, so it may be worth trying to use that last processor breakpoint slot and seeing if things don't fall apart.
Shakkan
March 16th, 2008, 16:34
Plant an INT3 and use a VEH would be easy, but planting an INT3 == modifying code ==> PunkBuster angry. :\
Regarding the debug registers, that's a good question if SafeDisc uses them all. I need to check that out properly. As soon as my SEH would be called, the application would crash. Maybe I'm doing something else wrong that has nothing to do with SafeDisc.
A quick question since you seem familiar with hardware breakpoints: by default, do hardware breakpoints cause single-step exceptions (i.e. execute the first instruction at the specified address in debug register and then pop the exception, allowing me to continue normal execution of the program)? I recall that with INT3 + VEH, you need to set EFlag to 0x100 to have such a behaviour, am I mistaken? If so, would you be so kind as to enlighten me?
Thank you!
disavowed
March 16th, 2008, 17:06
i forget the actual exception thrown when hitting a hw bp (and i'm too lazy to look it up), but yes, the exception is only caught by the debugger AFTER the instruction responsible for the exception has already executed (unlike software bps that get thrown to the debugger BEFORE executing the target instruction).
dELTA
March 17th, 2008, 04:24
Shakkan, if you're uncertain if SafeDisc is the culprit or not, maybe you can do some experiments on an un-SafeDisced copy, and then use your result on the real copy once all non-SafeDisc related problems have been solved?

Shakkan
March 17th, 2008, 07:59
Damn right. I'm trying to skip steps here. :\
Thank you.
Admiral
March 17th, 2008, 09:09
Hardware breakpoints do indeed rasie a SINGLE_STEP exception, but IIRC there are some occasions where the exception is raised before the instruction is executed, rather than after. I think this is the exception to the rule (no pun intended) but I believe certain REP instructions will trigger the break prior to their execution. It is for this reason that the Dr7 register contains a flag to specify whether the instruction has completed or not. This information is all being dredged from the depths of my memory so I assume no responsibility if there are technical inaccuracies

.
For clarity, disavowed's 'software' breakpoints in that last post are the guard-page type. By contrast, INT 3 breakpoints (also known as software) trigger the exception
after execution.
Shakkan
March 17th, 2008, 10:36
Hello again,
I stopped messing around and made a simple test project to validate my screwups. Admiral, you are right, hardware breakpoints trigger the exception BEFORE instruction execution. That's why I get an infinite loop with the test snippet I posted at http://pastebin.com/m6bbff83 ("http://pastebin.com/m6bbff83"). My console gets filled with "SEH CALLED" and "EIP: 2348985" heh
The solution I would see is remove the breakpoint once I catch the exception in my handler, then set EFlags to |= 0x100 to activate SINGLE_STEP tracing (so it will execute 1 instruction and then break), resume execution by returning EXCEPTION_CONTINUE_EXECUTION and then catch the STATUS_SINGLE_STEP exception and put the breakpoint back at the previous address. Am I being clear? heh
Two things I'm wondering:
#1 To catch the STATUS_SINGLE_STEP exception generated by single-step tracing, I would need a VEH to catch it for sure since it has precedence over SEH, right? Also, I don't even know if SEH handles STATUS_SINGLE_STEP exceptions.
#2 If I have a VEH to catch the STATUS_SINGLE_STEP exception and set the hardware breakpoint again at the previous instruction address, I need to have the concerned thread handle memorized since debug registers are set per thread context, correct?
I will play with all of this right now. If anyone has anything better to suggest besides the "set hardware breakpoint + enable single-step tracing/remove breakpoint + catch STATUS_SINGLE_STEP exception/re-set breakpoint" proposition, please let me know.
Thank you all for your constructive replies,
Alex
Shakkan
March 17th, 2008, 15:29
Hi,
It does work just fine now _without_ SafeDisc. I have the SEH catch the exception triggered by the hardware breakpoint, enable single-step mode and disable the hardware breakpoint. Then I have a VEH catching the single-step exception, disabling single-step mode and enabling hardware breakpoint back.
When used with a SafeDisc-enabled exe, the application freezes as soon as a breakpoint is hit.
I need to look at PAGE_GUARD now. Can it be set on a code segment (so breakpoint triggers once a method is called instead of when a data segment of memory is read or written to)?
Thanks again.
** EDIT ** I tried all 4 debug registers. No go. Damn SafeDisc...

disavowed
March 17th, 2008, 19:41
Quote:
[Originally Posted by Admiral;73408]For clarity, disavowed's 'software' breakpoints in that last post are the guard-page type. By contrast, INT 3 breakpoints (also known as software) trigger the exception after execution. |
actually, i was referring to int 3 breakpoints. i suppose it's debugger-dependent, but ollydbg breaks on the int 3 before the break-pointed instruction is executed. it's possible for a debugger to receive the int 3 exception, replace the instruction with the original, single-step it, then transfer control to the user, though i've never seen a debugger that does this.
Maximus
March 17th, 2008, 21:00
exceptions are of 2 class: fault (EIP stays before faulting instruction) and trap (EIP point to next instruction).
Tracing, HR and HW is a trap-class and your EIP points to next instruction, HE is a fault.
They raise the same interrupt (INT1), but the raised condition is different. You discover the condition by examining DR flags.
The REP instructions cause some problems due to CPU inherent 'memory optimization' with HW breaks: on older CPUs you had a flag to force CPU to 'step them' right and sequentially, but today it simply does not work anymore. So, dont think to break with HR/W at the middle of a rep in a 'precise' way.
@disa: olly break before instruction gets executed because it overwrites the instruction with CC. So the instruction (CC) gets executed, and EIP is effectively after CC. Restarting an instruction requires a fair amount of work for a debugger (set EIP-1, remove the break, place the original byte, single step silently the instruction if the user asked to run, place back the breakpoint if it's not a 'one-shot', and finally run if the user asked to run etc.).
At least, this is the way my debugger resets the breaks. I bet olly is not very different, there are not many ways to do this.
@OP: maybe coding an INT1 'interleave' driver to slide past its silly antidebug? (unless you are in Vista, which would tell you "bad, bad boy" for hooking IDT).
Shakkan
March 18th, 2008, 07:55
Well, the solution must be compatible with XP x86/x64 and Vista x86/x64. :\
PAGE_GUARD is too costy. As Admiral mentionned, guarding a full page would cause a big penalty performance since it's an executable file and there's a lot of chance that most nearby addresses get called very often.
Anyone has a miraculous solution for me? Just to 'refresh' what I want to do: I need to be notified of when EIP passes through a certain address (i.e. 0x005C5600) during gameplay but I CANNOT modify the executable at all or PunkBuster will kill me. Also, I can't use hardware breakpoints because SafeDisc uses them all.
Thanks again,
Alex
disavowed
March 18th, 2008, 10:20
another option: how hard is it to "fix" punkbuster so that it won't be unhappy with software breakpoints in the target?
Shakkan
March 18th, 2008, 10:42
Quote:
[Originally Posted by disavowed;73436]another option: how hard is it to "fix" punkbuster so that it won't be unhappy with software breakpoints in the target? |
I know it's a possible solution, but keep in mind that PunkBuster is a widely used software to prevent hacking. Even though my purpose is 100% legitimate, I'm no better than the cheaters in PB's eye (even if it's for one little INT3). PB is constantly updated and the software that I will distribute will be used by end users. Playing the cat & mouse game with PunkBuster really isn't my preferred choice. Imagine once PB releases a new version and the end users using my addon get kicked because of file/memory corruption.

PB runs a md5 check on the whole executable in memory.
But thanks for the suggestion. I'm running out of ideas here. Help!

Admiral
March 18th, 2008, 10:50
Your work is cut out for you, and there's really no easy fix. Both PunkBuster and SafeDisc are designed to stop exactly this kind of behaviour. You simply won't be able to fight much of a battle on both of these fronts without some serious reinforcements

. I take it that assuming a power-role from kernel-mode is out of the question, right?
Shakkan
March 19th, 2008, 08:36
Hi Admiral,
That's great news! ...just kidding. heh
Anyhow, I saw it coming, although I'm not giving up. Why do you assume that your proposition is out of the question? Can you resume briefly what is "assuming a power-role" from kernel-mode? I don't expect you to walk me through (I'm not that kinda guy :|), I will do my homework, but care to explain me the big idea?
Thanks again!
Alex
dELTA
March 22nd, 2008, 06:57
Shakkan, I think the kernel-mode suggestion is related to what Maximus mentioned earlier, which would as mentioned be of some trouble on Vista (due to PatchGuard).
Btw, as a more general question, isn't there really some still currently working good way to disable PatchGuard on Vista? There has been many in the past, so I would suggest a google on "disabling PatchGuard" or "bypassing PatchGuard" for some possibly interesting information. Since the users of your software would most likely be willing to do whatever it takes to make it work on their computers, over which they have full administrative control, they would most likely be able to do this without any problems, no matter how roundabout the procedure might be.
Maybe Alex would like to contribute some of his more than deep insight on this particular issue here? (for those not familiar with Alex's experiences in this field, see the following starting point for the whole PatchGuard circumvention hoopla: http://blogs.zdnet.com/security/?p=447 )
Another Vista related thought: Now, if IDT patches and other miscellaneous trickery isn't possible on Vista for you, it shouldn't be possible for SafeDisc either, right? So, I would guess that the SafeDisc protection of the e.g. the debug registers etc isn't as fierce and hard to circumvent on Vista as on other operating systems then? Thus, you might be able to create two versions of your software (wrapped into the same program, with OS auto-detection for on-the-fly choice of which if you will). One kernel-driver based version for non-Vista OSs, and one non-kernel-driver based version for Vista, which might in turn not even require this in the first place to bypass this aspect of the SafeDisc protection, due to the reasons just mentioned?
Anyone willing to share more info or counter arguments to this hypothesis?
One more thing too: As far as I'm understanding this, you are only assuming that the PAGE_GUARD method would incur an unacceptable performance hit? This might not really always be the case, it depends completely on the layout of the code. If the adjacent code (i.e. the code in the same page as the interesting break address) is only rarely executed, it might very well work just great. I think you should implement this method and try it at least, since it will most likely be a working solution in at least some/many cases.
aionescu
March 22nd, 2008, 11:17
dELTA: Disabling Patchguard isn't a reliable solution, imho.
Also, the DRs aren't really "protected" by Patchguard -- they're just reset during Patchguard's code paths.
The solution Shakkan wants to be looking at is loading something in kernel-mode to use the DRs and patch out/ignore SafeDisc attempts to gobble them up.
dELTA
March 22nd, 2008, 13:33
Thanks for your insights Alex!
Some clarification though:
Quote:
[Originally Posted by aionescu]Also, the DRs aren't really "protected" by Patchguard -- they're just reset during Patchguard's code paths. |
Yes, what was discussed was rather the following "chained problem", where only PatchGuard is "indirectly" responsible for not allowing us to use the debug registers, by multiple layers of implication:
PunkBuster is monitoring the target, and it is constructed in such a way that the only viable/practical method to acquire "breakpoint-like functionality" in games monitored by it is to use hardware breakpoints (well, or at least that's what the collected participants of this thread seems to be able to conclude anyway, including myself).
SafeDisc is protecting the target, and it is constructed in such a way that it uses assorted trickery (including ring 0 such) in order to prevent you from making use of any of the debug registers, and thus also implicitly preventing you from using any hardware breakpoints on the target.
The method that has been suggested to neutralize this show-stopper feature of SafeDisc is to subvert it by means of miscellaneous kernel-level hooks (remember that we cannot remove or patch the SafeDisc protection directly, since this would make PunkBuster unhappy and bring us back to square one, where it has already been concluded that attempting to neutralize PunkBuster itself is not a viable option
).
The working hypothesis is then that the implementation of such effective hooks can only be acquired by means of IDT patching or similar.
The next assumption is that "IDT patching or similar" will always be prevented on Windows Vista by the PatchGuard feature of the operating system, which will thus, implicitly, prevent this angle of attack in its entirety.
The next logical step to be concluded was to neutralize PatchGuard, in order to unwind this annoying chain of interdependent show-stopping details, and thus be able to reach our initial goal by means of making SafeDisc allow us to use hardware breakpoints without actually patching it directly.
I'm not a ring 0 guru at all, so the hypotheses and assumptions listed above might very well be false at some places, which would indeed just make me happy. In that case it would be great if someone more knowledgeable could step up and let us know. Alternatively, if someone with deeper knowledge of SafeDisc would know of a good way to neutralize its hardware breakpoint meddling without either patching the memory areas affected by the PunkBuster checksums, or using "IDT patching or similar" that will be stopped by PatchGuard, that would be a great possible solution too.
Quote:
[Originally Posted by aionescu]The solution Shakkan wants to be looking at is loading something in kernel-mode to use the DRs and patch out/ignore SafeDisc attempts to gobble them up. |
Considering my explanation of the problem above, do you still think this is a viable/possible option? In that case, with just a few words to push people in the right direction, how?
Quote:
[Originally Posted by aionescu]Disabling Patchguard isn't a reliable solution, imho |
The problem at hand seems likely to force us to settle with "the least unreliable solution" rather than "a reliable solution", which is why I went down this path to begin with. When you say that it isn't reliable, do you mean it in a "it's-a-too-ugly-hack-although-working" way, or in a "there-are-strictly-technically-no-known-ways-what-so-ever-to-disable-PatchGuard-today" way?

Also, remember that the persons who would like to do this have total (including physical) control of their computers.
If nothing else, I really think it should be possible to do such a thing by either making use of a direct kernel memory patch with a modified version of the firewire DMA vulnerability Windows login bypass exploit (http://storm.net.nz/projects/16), or by making use of an pre-boot rootkit, like e.g. the BootRoot boot sector rootkit that eEye makes available with source code and everything (http://research.eeye.com/html/tools/RT20060801-7.html ... hmm, server not available at the moment, here is the Google cache anyway (remove linebreak in URL): http://64.233.183.104/search?q=cache:NGXyna1aMscJ:research.eeye.com/html/tools/RT20060801-7.html+
eeye+bootroot&ct=clnk&cd=1), and which has also already been used to create apparently quite stable malware code in the wild (http://www.woodmann.com/forum/showthread.php?t=11370). Maybe that's a project that someone around here would think was a fun and worthy challenge?
These last two suggestions are of course quite extreme measures, but I like to conquer all problems and limitations, no matter the means necessary, and I can only assume the same about game hackers.

Maximus
March 22nd, 2008, 19:53
mmh... I never faced punkbuster (...doing other things), but for what I've read, it uses DR0/3 with values, or at least it monitors them.
Rethinking, Vista won't allow PB to thunk INT1, so probably this is true on XP too.
This means that DR registers can be used in 2 ways. They can keep "Data" or "R3/R0 Transition Switch". Supposing that PB guys do not unsafely jump back and forth the Privilege Machine using hardware breakpoints and some hook (which would be very lame, unsafe and not very original), DR registers can only contain data used by PB.
This brings to the following:
* IF they are only used at R3, hook Get/SetThreadContext, KiUserDispatchException and you are done.
* on R0... mmh... It depends on the way they do the R3/R0 transitions. Doers the R3 application accesses R0 normally? (i.e. not rogue INT1, direct calls to strange INTs, hooked SSDT etc.) However, it *might* be possible to code a Filter Driver for PunkBuster, that restore/save whatever you need. This would make it fully compatible in Vista, too. Just take some simple filter driver code, hook all IRP_MJ used by PB and make them restore the states you need, then set a completion routine that set your needed stuff back as you wanted. Witha bit of luck, it may suffice.
Shakkan
March 22nd, 2008, 20:07
Hello guys,
I just want to let you know I REALLY appreciate all your inputs on this subject. Extremely constructive. I can't keep up with the thread right now as I am busy with guests, but I will as soon as tomorrow and get back to you. I got some reading to do.
Thank you!
P.S.: Sorry for the useless post. I just wanted to make a quick one to let you know I am still following the thread (I've been checking for possible replies every few hours

JMI
March 22nd, 2008, 20:08
Since the link is down, I'm attaching the eEye "BootRoot boot sector rootkit" that dELTA mentioned.
Regards,
xtc
March 23rd, 2008, 05:57
Thought I'd make a minor correction, given the subject title...
You're correct that member pointers cannot be cast to and from.
However pointers to member pointers are not similarly restricted.
I've written a demonstration, similar to what you were trying to accomplish:
Code:
#include <iostream>
class Test {
public:
typedef void (Test::*MemberPfn)(void);
void Target(void) {
std::cout << "Test::Target()" << std::endl;
}
};
class MyTest {
typedef void (MyTest::*MemberPfn)(void);
static MemberPfn m_targetPtr;
public:
static void* GetHook() {
static MemberPfn pfn = &MyTest::Hook;
return *(void**)&pfn;
}
static void SetTarget(void* ptr) {
*(void**)&MyTest::m_targetPtr = ptr;
}
void Hook(void) {
std::cout << "MyTest::Hook()" << std::endl;
if (this->m_targetPtr) {
(this->*m_targetPtr)();
}
}
};
MyTest::MemberPfn MyTest::m_targetPtr = 0;
int main(int argc, char* argv[])
{
Test::MemberPfn targetPtr = &Test::Target;
MyTest::SetTarget(*(void**)&targetPtr);
*(void**)&targetPtr = MyTest::GetHook();
Test* test = new Test();
(test->*targetPtr)();
delete test;
return 0;
}
Your second problem seems twofold:
1) SafeDisc is messing with the debug registers.
Have you considered determining the nature of this usage?
Where are they used? How are they used? Could the usage be circumvented/simulated?
The DRx accessing/mutating code is located in SafeDisc's driver.
Usermode applications and drivers have a limited number of ways of communicating with each other, the most common of which is the request/response model of DeviceIoControl. Here's a conceptual summary of the process:
The application opens a symbolic link (CreateFile) to a device of the driver in question. Prepares a request in the form of a device specific io control code and optionally data required to cary out the request. The request is sent to the driver using DeviceIoControl.
The driver receives the request through a callback function (IRP_MJ_DEVICE_CONTROL) specified in it's DRIVER_OBJECT. The callback is passed an io request packet (IRP) which contains the request information. The callback will then carry out the request and as a response return a) a status code indicating if the request was successful or not and optionally b) data generated as part of the request.
The os will then perform a number of tasks depending on the situation. If the callback returned an error status code, it will convert it to a usermode error code and set that in the last error variable. If data was provided as part of the response, it will be copied to the output buffer specified in the DeviceIoControl call. And finally it will return from the DeviceIoControl call.
Given this model, what options do you have for isolating "malicious" requests to the driver?
2) You've got punkbuster watching over your shoulders.
Any solution that you can come up with for trapping execution within executable images monitored by pb, will be of interest to pb, whether it currently detects it or not.
From Ring 3 it seems you have little options but to somehow circumvent pb. This obviously requires a familiarisation with the inner workings of pb.
I'd suggest heading over to http://forum.gamedeception.net for more information about pb.
For Ring 0 you've got a few more options, however knowledge of driver development is required.
Assuming that pb does check the debug registers, you'd have to hide them. This could be done by hooking the kernel level apis responsible of carrying out Get/SetThreadContext's doing. Or if pb is accessing them directly, by using the global detect flag to trap such access.
"Raising The Bar For Windows Rootkit Detection" (http://www.phrack.org/issues.html?issue=63&id=8#article) outlines a method for hiding executable code which is designed to solve your specific type of problem. However, I'm not sure if this approach can be applied/adapted to Vista or x86-64 (I'm clueless about both).
These are the only immutable methods of trapping execution that I know of, that is, debug registers and page table modification.
What it ultimately comes down to, I think, is a choice between learning driver development or researching punk buster.
dELTA
March 23rd, 2008, 06:08
Very nice insights Maximus and xtc!
I'm a little bit confused over one previous thing that is made current here, and just want to clear it up:
Quote:
[Originally Posted by Shakkan]It does work just fine now _without_ SafeDisc. I have the SEH catch the exception triggered by the hardware breakpoint, enable single-step mode and disable the hardware breakpoint. Then I have a VEH catching the single-step exception, disabling single-step mode and enabling hardware breakpoint back.
When used with a SafeDisc-enabled exe, the application freezes as soon as a breakpoint is hit.  |
Shakkan, please confirm that I'm right in assuming that PunkBuster will never allow an un-SafeDisced exe to begin with, correct? And that means that you performed this test without PunkBuster being active, in a non-live situation (thus, still useless for your purposes), correct?
Otherwise it really seems that the easiest solution would just be to use an un-SafeDisced version of the exe when performing whatever stuff it is that you're doing? But again, it seems very strange that PunkBuster would allow the un-SafeDisced exe to begin with?
Quote:
[Originally Posted by Maximus;73549]mmh... I never faced punkbuster (...doing other things), but for what I've read, it uses DR0/3 with values, or at least it monitors them. |
This quote is what made me think about this unclarity to begin with, since it would be proven false by Shakkan's statement above if PunkBuster was running at the time of the described test. If the answer to my question above (i.e. if the successful test with the un-SafeDisced exe was performed with PunkBuster active) is yes, then I guess this cannot be true (i.e. that PunkBuster monitors DR registers)? But once more again, I really don't think that PunkBuster would allow an un-SafeDisced exe to begin with, right?
Quote:
[Originally Posted by Maximus;73549]Rethinking, Vista won't allow PB to thunk INT1, so probably this is true on XP too. |
Yes, this is the line of thought I was having above too, only that I wasn't a big enough ring 0 buff to deduce the rest of the details that you concluded, but rather only the same end result on a very conceptual level.
And xtc, the SafeDisc driver communication subversion suggestion is exactly the kind of thing I had in mind with the following, thanks!
Quote:
[Originally Posted by dELTA]Alternatively, if someone with deeper knowledge of SafeDisc would know of a good way to neutralize its hardware breakpoint meddling without either patching the memory areas affected by the PunkBuster checksums, or using "IDT patching or similar" that will be stopped by PatchGuard, that would be a great possible solution too. |
Shakkan
March 23rd, 2008, 22:05
Quote:
[Originally Posted by dELTA]One more thing too: As far as I'm understanding this, you are only assuming that the PAGE_GUARD method would incur an unacceptable performance hit? This might not really always be the case, it depends completely on the layout of the code. If the adjacent code (i.e. the code in the same page as the interesting break address) is only rarely executed, it might very well work just great. I think you should implement this method and try it at least, since it will most likely be a working solution in at least some/many cases. |
You are right. I am assuming, but the address I want to monitor is part of a code segment (not data) so it's highly likely that adjacent instructions get called very often. Yet, I admit that I should try it to validate or invalidate what I assume. PAGE_GUARD also works with code segments, not just data segments, right?
Quote:
[Originally Posted by Maximus]* IF they are only used at R3, hook Get/SetThreadContext, KiUserDispatchException and you are done. |
Unfortunately, it's used at a lower level. DeviceIoControl is used by SafeDisc for DR manipulation. :\
Quote:
[Originally Posted by xtc]Usermode applications and drivers have a limited number of ways of communicating with each other, the most common of which is the request/response model of DeviceIoControl. |
That's right. SafeDisc DOES use DeviceIoControl to play with the debug registers. I did a bit of research and some guy who disassembled SafeDisc code could locate the calls to DeviceIoControl.
Thank you for the explanation and distinction on member pointers and pointers to member pointers. However, my initial issue was to hook a member function to which the only thing I got is a bare address (no code to do a &Class::Method). Fortunately, I previously found a solution to this (the code involves converting a _thiscall to _stdcall by pushing ECX to the stack and put a void* as first parameter on the hook function declaration). PunkBuster made this all pointless though, but still interesting to know.
Quote:
[Originally Posted by dELTA]Shakkan, please confirm that I'm right in assuming that PunkBuster will never allow an un-SafeDisced exe to begin with, correct? And that means that you performed this test without PunkBuster being active, in a non-live situation (thus, still useless for your purposes), correct? |
I can confirm it. An un-SafeDisc'd version of the executable would result on a different md5 when PB decides to do a routine exe scan.
Quote:
[Originally Posted by dELTA]This quote is what made me think about this unclarity to begin with, since it would be proven false by Shakkan's statement above if PunkBuster was running at the time of the described test. If the answer to my question above (i.e. if the successful test with the un-SafeDisced exe was performed with PunkBuster active) is yes, then I guess this cannot be true (i.e. that PunkBuster monitors DR registers)? But once more again, I really don't think that PunkBuster would allow an un-SafeDisced exe to begin with, right? |
Well, I am to blame for this. Sorry.

I know for a fact that SafeDisc uses the DR but I didn't try my code (hardware bp + SEH) with an un-SafeDisc'd executable online where PunkBuster is active. Since PB does not compute a md5 every second on the executable, I CAN test an un-SafeDisc'd version online quick and see if PunkBuster is a culprit too. I will try that too on Tuesday to get more info.
To everyone:
Obviously, you guys are way above my league. IDT patching, driver development knowledge, PatchGuard, all around Ring 0 knowledge. I will continue reading the links that were posted here but
anyone knows some good resources (ebooks, articles, etc.) about basic information on R0/R3/IDT patching/etc. (i.e. the kind of stuff you expect me to know so I can follow you) so I can educate myself further and further? Please don't throw in the towel, I'm loving the contribution by this community. I will do my homework and won't give up.

dELTA
March 24th, 2008, 05:58
One important conclusion here is that if PunkBuster uses the debug registers itself, neutralizing SafeDisc in a not-by-PunkBuster detectable way still won't have accomplished anything, and then you're back again to the two remaining options of trying the PAGE_GUARD method (which I guess might very well be detectable by PunkBuster too?) or going after PunkBuster directly.
I suggest that you verify this before putting any large amounts of work into attacking SafeDisc.
Again regarding the PAGE_GUARD assumptions, yes, it can be done on code, and no, 4096 bytes of code really isn't that much at all in a big game executable, so if you're lucky, none of that code is executed very often, which might lead to acceptably low levels of performance loss. I'd say that currently, everything points in the direction of trying out this method, before doing anything else.
disavowed
March 26th, 2008, 21:06
This idea is totally out of left field, but... if you're looking to mess with stuff going on inside of your target process but you can't mess with the primary executable's memory because of PunkBuster, what about patching the DLLs (either in-memory or on-disk)? For example, if the function you want to patch in your game calls Sleep(...) at some point, patch kernel32.dll's Sleep(...) function to do your bidding.
dELTA
March 27th, 2008, 03:58
That might indeed be a good way to approximate the desired breakpoint, if:
There is some such DLL/API function called close enough to the point of interest.
The originally desired breakpoint doesn't need to be exact, contrary to e.g. if you want to read some temporary memory data buffer etc exactly at this breakpoint.
PunkBuster does not checksum DLLs too, which I sadly assume is quite likely that it will?
I'm sure Shakkan can answer the first two questions right away, and possibly even the third? Does anyone else know the answer to the third question?
Admiral
March 27th, 2008, 06:38
Indeed, patching the DLL files themselves won't achieve anything, as PunkBuster's methods involve regular integrity checks, rather than memory-access protection. So such a disk-image modification will only ensure that PunkBuster gets angry at the soonest possible opportunity

.
dELTA
March 27th, 2008, 08:04
Damn, it almost seems like that PunkBuster program doesn't
want people to mess with the processes it protects, or something.

Shakkan
March 27th, 2008, 08:43
Hello,
Quote:
[Originally Posted by disavowed]This idea is totally out of left field, but... if you're looking to mess with stuff going on inside of your target process but you can't mess with the primary executable's memory because of PunkBuster, what about patching the DLLs (either in-memory or on-disk)? For example, if the function you want to patch in your game calls Sleep(...) at some point, patch kernel32.dll's Sleep(...) function to do your bidding. |
That could be a good idea. In my hook, I would check ESP and see if it was called by the wanted method. Though it would create overhead for all other calls to it but that's a small price to pay.
Quote:
[Originally Posted by dELTA]That might indeed be a good way to approximate the desired breakpoint, if:
1. There is some such DLL/API function called close enough to the point of interest.
2. The originally desired breakpoint doesn't need to be exact, contrary to e.g. if you want to read some temporary memory data buffer etc exactly at this breakpoint.
3. PunkBuster does not checksum DLLs too, which I sadly assume is quite likely that it will? |
1. That's something I can easily check. I don't know right now but I can figure this out soon.
2. Indeed, it doesn't need to be exact, as long as I'm notified somehow of a call to that method.
3. PunkBuster can't scan all DLLs, well known applications such as FRAPS and Xfire inject themselves into games and hook themselves into some DLLs such as Direct3D. FRAPS even use a system-wide hook. As far as I know, PunkBuster entirely scans the executable and a _part_ of Direct3D. That means that the suggestion by disavowed seems like a good one. Anyone can confirm or infirm my assumption about PunkBuster?
I still need to explore the PAGE_GUARD/VEH method and try an un-SafeDisc'd EXE online with SEH/DR method to see if PunkBuster also messes with DR's. I'm lagging behind but keep the suggestions coming, I will catch up. Just been busy recently.
Thank you.
dcskm4200
March 28th, 2008, 23:36
"eeyebootroot.zip"
password?
clockwork305
April 7th, 2008, 23:53
There can be a somewhat simple, if hackish, way to do this from ring3 if the situation is right. I've used it in the past to get around similar protection. Find two API calls, one executed directly before the code you want to hook, and one after. Hook inside the first API call, when the hook is called check the return address on the stack and see if it's your target area. If it is, install your hook. Do the same for the API after the code you want, just to uninstall the hook. Hooking inside or at the ret of the APIs can help avoid detection depending on if/how the APIs are checked, but beware of portability issues with that. Just my two cents.
Shakkan
April 8th, 2008, 19:17
Yeah, that's similar to a suggestion above from disavowed. In that case, as I mentionned, simply checking ESP would be sufficient, no need to hook at all since I only want to be _notified_ of the call, I don't need its parameter values and such. Anyway, hooking/unhooking would be unreliable, you never know when PB does integrity checks and that method would get called quite often as it is a "On Weapon Fire" method, called for every bullets that gets out.
So many things to try now, so little time. I have yet to validate all the suggestions that were made in that thread, but I'll NEED to find the time very soon. There's no way I'm giving up.
Thanks.
Powered by vBulletin® Version 4.2.2 Copyright © 2018 vBulletin Solutions, Inc. All rights reserved.