PDA

View Full Version : Warnings about reading process memory in Windows



maggotboy
11-01-2002, 03:11 PM
One thing to note about reading the process memory in Windows which has some disaster potential if Verant codes it right ...

Verant could call VirtualProtect() on a block of memory, essentially causing a trappable exception to occur if that memory is read. Using this method they could ...

- Detect when the memory holding the key is read
- Handle the memory exception error and report back to Verant quietly that the encryption key was read -- possible repurcussions and/or potential for being banned!
There's some serious possibilities of being detected here, which merit another look at this method of obtaining the key.

high_jeeves
11-01-2002, 03:21 PM
By my reading:

VirtualProtect is for memory blocks that have been allocated using VirtualAlloc or VirtualAllocEx. The key memory location can therefore not be locked in this way.

--Jeeves

throx
11-01-2002, 04:27 PM
Unless, of course, they use VirtualAlloc to allocate memory for the key block.

Alternately you can write a device driver that does the same thing to an arbitrary memory area.

Of course, then the SEQ can write another driver which counters this, to which Sony writes detection and nullification code for the SEQ driver. The SEQ changes their code, Sony changes their code etc.

End result: SEQ works (at best) half the time and at worst reports your usage to Sony to have your account flagged for observation.

Nova411
11-04-2002, 07:42 PM
After some experimentation heres what I found : ReadProcessMemory will not trigger a PAGE_GUARD exception in a different process, it simple returns failure. However, if you want to you can modify the protect flags with VirtualProtectEx from an external process, so you could feasably turn off the guard, read the memory, and turn the guard back on.

The catch is however, that if they're checking the status, and you un-guard it, then they know something funny is going on. But of course theres another catch, which is they can't guard it because they need to read it constantly! :) Guarded memory's purpose is primarily to safeguard against memory access and such, so they'd be tripping the guard flag constantly, either that or they'd have to constantly add and remove the protect flag. Either way, worst case scenario for us the flag is STILL coming on and off constantly, so even if they *do* this which seems more and more insane, all we would have to do is spam ReadProcessMemory until one of them gets through. (tripping the guard also removes it - its a one-shot deal) Since ReadProcessMemory automatically fails on a guarded memory block, we never trip, and sooner or later they have to open it up.

I'm not sure if a kernel-mode driver would bypass this guarding or not, anyone else know?

MisterSpock
11-05-2002, 07:28 AM
From a lengthy conversation I had with a Windows programmer the other day, this is what I was told. Please note, I have not independently verified it, but will work on writing some test applications to verify.

While it is possible for an application to know that its memory space is being accessed, it is not possible for it to know whether it, or another process is accessing the memory.

There are two main ways that the presense of such an application (mem reader) can be detected.

I'm a little reluctant to post either one -- we needn't give them any ideas. I can discuss one of them safely, I think. Moderators -- please delete or edit if you feel it necessary.

However, one of them is fairly well known and one that they have tried -- task list scanning. They would need to know the name of the process and/or attempt to fingerprint (via scanning the HDD) the exe that launches the process.

The second one is more subtle, and one that I will not discuss in the open. However, suffice it to say that it is something we could detect and bypass.

throx
11-05-2002, 11:07 AM
If you are going to read the key (which you only need during New Spawn and Zone packets) then you just use VirtualProtect to take the protection off, read the key (onto the stack is a good place) and put VirtualProtect back on. Simple.

There's dozens of ways to detect a DLL/EXE with access to your memory space. There's dozens of ways to counter each of them. Then there's ways to detect and disable the countermeasures.

lostinspace
11-07-2002, 06:44 AM
Can you post link to anything that shows how it is possible for user application to detect sniffer ?

Would be helpful to decide what not to do in sniffer, or what to try and check. So far I didnt find some info on how they can really intercept it, or detect memory reading.

Not saying that it can not be done, but it would be more productive if people post exactly how it can be done and help rest of sniffer program users guard agains it, instead of just repeating "there are number of ways to detect" and not showing any of those ways . I'm sure that Sony programmers can find info from other resources too, so examples of ReadProcessmemory detection could only help sniffer users.

lostinspace
11-11-2002, 07:29 AM
Btw, I also tested if VirtualProtect will trip on ReadProcessMemory, and it doesnt. Still, it will require changes in sniffer if SOE decide to put key in memory allocated with VirtualAlloc, with PAGE_GUARD. While it doesnt trigger alarm, such memory can not be read with ReadProcessMemory.

It is fairly easy for SOE do do following:
1- pKey = VirtualAlloc
2- write key to pKey
3- VirtualProtect (pKey, PAGE_READONLY | PAGE_GUARD )

And on every read, they do:
1- VirtualProtect (pKey, PAGE_READONLY, oldProtect)
2- if oldProtect <> PAGE_READONLY | PAGE_GUARD --> HACKERS !!
3- read Key from pKey
4- VirtualProtect (pKey, PAGE_READONLY | PAGE_GUARD )

Above code is fairly fast, and will do two things: catch badly designed sniffer, and also will not provide enough time frame for existing sniffer programs to read key. Even if you run sniffer in dead loop waiting for succesful read ... because then you will block EQ and other win processes execution.

So new sniffer would need something like this:
1- hPrc = OpenProcess(PROCESS_VM_READ or PROCESS_VM_OPERATION ...
2- ReadProcessMemory(hPrc, <addr of pKey from above> , p2 ...
3- VirtualProtectEx(hPrc,p2,8,PAGE_READONLY,oldPr)
4- ReadProcessMemory(hPrc, p2, <addr of our key buff> ...
5- VirtualProtectEx(hPrc,p2,8, oldPr .. // return guard !
6- CloseHandle(hPrc)

With this modified code, sniffer would be able to read VirtualProtect key, and will also be fairly hard to detect , from same reason old sniffer would have hard time to read locked memory - and that is short window of changed guard status. Above modified sniffer code execute in about 20 microseconds on 1.6GHz, or 0.02 ms. It is highly inprobable that potential new SOE key read procedure (which would be invoked fairly rarely) would happen exactly at same moment as those 20us for new sniffer read code. Only way for SOE to catch guard change would be to run VirtualProtect in dead loop and wait for change - which would freeze game for some period.

Well, this is all theoretical discussion - there is no indication that SOE will change way it store key. But if it does , and use VirtualProtect, this is how it could be still read, with reasonable safety.

I still believe it is easier for SOE to read packets and files writen from PC and not generated by EQ, and check if they contain current key ... since both implementations on SEQ side expect plain key in data. I already posted how extremely simple encryption method used between sniffer and SEQ would prevent that. Even as simple as XOR of key data with shared number. Or much better and only slightly harder to code is option to reserve first 2 bytes in data (written in key file to SEQ, or sent ovet UDP) for offset where in data EQ key is starting, and then all data XORed with shared key. First method could be detected by SOE catching file/packet and XORing with their current key...and then catching later new packet/record and XORing again with their new current key , and if both results are same, they can say packets contained EQ key. With added offset in first 2 bytes of data, that option is not possible.

Maybe I'm too paranoic, but above option is few lines of code, and would make me feel bit more secure :)

quackrabbit
11-11-2002, 10:36 AM
It is highly inprobable that potential new SOE key read procedure (which would be invoked fairly rarely) would happen exactly at same moment as those 20us for new sniffer read code.

Doesn't eqgame.exe need to read this memory for every packet they need to decode? Which would be pretty frequent - would it not?

throx
11-11-2002, 04:45 PM
eqgame.exe only needs the key for zone packets and new spawn packets, which may or may not be frequent depending on the zone you are in.

Monitoring files and sockets on the computer is probably a bit invasive and may land them in legal hot water (depending on the change to their EULA). They could easily change their license to permit them to scan your computer for hacking software - after all it *is* their service and if you don't want it then you don't have to agree to their terms.

If I was Sony, I'd hook the OpenProcess() call (preferably in kernel mode) and test it for my process ID, returning a (or flagging something). This is a relatively trivial exercise if you look at some of the source code available at sysinternals.com, MSDN, or in the book "Inside Windows 2000".

They could be as sneaky as they liked about it really - return a failure, return the wrong handle, monitor the ReadProcessMemory() calls following and do all sorts of nasty stuff. The real question is whether it's worth the few hours programming time it would take them to implement something like this. Personally if I was working for Sony I'd toss it into a patch sometime just to get some metrics on who was monitoring the session key. I think I could make a reasonably good business case for it.

bonkersbobcat
11-11-2002, 05:06 PM
While it may be just a few lines of code, hooking an OS call is never trivial. You introduce risks for system instability. An EQ installation can be touchy anyway, would they risk making it less stable and having to deal with the support costs?

RavenCT
11-11-2002, 07:38 PM
One other thing to remember (And, yes, again, I'm a network dude and not a programmer) is that they HAVE to have the thing run under multiple different OS's...

They already had a stink when the excluded Windows 95, but if the memory monitoring tricks you would use are for Windows 2000/XP only, that won't help them with Windows 98/ME...

Although, if what your talking about works under both sets of O/S's, then I'm just typing to hear myself type :)

Just another thought...

MisterSpock
11-11-2002, 09:47 PM
Great point, Raven!

We must keep in mind that they must design to the lowest common denominator -- Win98. Memory management between these two platforms is drastically different...

futuro
11-11-2002, 10:24 PM
A question :

How would running EQ under Winex affect this whole memory scanning discussion? Do the same memory protection schemes operate the same under Linux/Winex?

Just wondering.

mvern
11-12-2002, 02:36 AM
I think wine handles it pretty much just like win98. As far as their being limited by having to support multiple OS's, that really isnt the case, its trivial to write conditional code that only executes on nt/2k/xp, and they've already done it (the acl security stuff).

lostinspace
11-12-2002, 05:18 AM
Throx, can you post some link to those examples. So far all examples of hooking OpenProcess that i found required change of some system DLL. While it may be trivial for end user to do that, it is not so trivial for application, not to mention it seems like very intrusive thing ( changing integral part of OS, risking system instabilities , .... ).

Was there any example in those sources how they can hook on OpenProcess or ReadProcessMemory without changing OS ?

zarzax
11-12-2002, 09:14 AM
Here is a good article about API hooking.

http://www.codeproject.com/system/hooksys.asp

throx
11-12-2002, 01:46 PM
To answer a few of the posts:

First, thanks zarzax for the link (excellent article btw). I knew it was Cogswell and Russinovitch that developed the kernel level hooking (for regmon) but forgot I'd read about it in DDJ. The source code for regmon is available at Sysinternals.com so the methods for hooking any API are freely available.

Suggesting that system wide hooks will result in system instability is nonsensical. Many apps you run currently do it to monitor global hotkeys, allow floating windows to work properly and other fun things. Sure - they don't hook APIs at the level regmon and the like do but there's no evidence to suggest that any more instability would be introduced. After all, it's only a comparison of a couple of dwords and then passing the call on to the original function.

Yes - you need separate code for 9x over NT. This is trivial to do. 9x is actually a lot easier to hook than NT based systems thanks to the near non-existant memory protection 9x offers.

In my mind, the whole concept of building the app yourself and making filenames and/or socket numbers different is paranoia in the wrong direction. Fundamentally the common factor to all current keysniffers is the OpenProcess(), ReadProcessMemory() call. Detect that and you can immediately flag all key sniffers, macroquesters or even magelo users if you want. Like the devs said, it's the risk you have to be willing to take.

If you aren't willing to lose your account and walk away from Everquest then don't run a key sniffer.

Of course, Sony actually has to care enough to detect it first...

baelang
11-12-2002, 03:04 PM
Originally posted by throx
If you aren't willing to lose your account and walk away from Everquest then don't run a key sniffer.

If you aren't willing to lose your account and walk away from Everquest then... you probably really ought to think about a 12-step program.

throx
11-12-2002, 04:45 PM
:-)

Good call.

MisterSpock
11-13-2002, 06:29 PM
Okay -- I've had a couple of days to digest the article on User mode API hooking.

This would not be an effective way to detect the APIs in question.

For this to work, the would have to scan the process list and perform the DLL injection (or jump table mods, etc) to *every* application other than eqgame.exe (etc) on the process list...

The hook in user mode applications (which is the subject of the article) are inserted into the code that will be making the API call. In this case, the code making the API call is the keysniffer. In short, they would have to hook your keysniffer. Again, this would require process list scanning, and hooking *every* application on the list that appears to be unknown or suspicious.

It would be completely ineffective against those keysnarfers that are not in memory or in the task list when the hooking procedure took place. If you launch the "dirty" process from a "clean" process (a service routine), either via a spawn or a dll load, or similar trick, it is even more unlikely that it would be hooked.

Even if they DID manage to hook every single application, we could do the exact same trick in our keysniffers and have them hook, and so forth... last hook wins... So I don't think this is a serious threat.

Kernel-level hooks are a different subject... I'll comment more on these in another message.

throx
11-15-2002, 11:36 AM
Yeah - user mode hooking has it's problems. There's a registry key you can set which will inject a specified DLL into every process that is started, but you have to manually inject it into all processes which are already started which pretty much sucks.

Kernel mode hooking would be the way to go and far more reliable.

LordCrush
11-15-2002, 06:25 PM
Hmm which key? - i want to check it in my sniffer, can you plz post it ... would be more easy than to search... SoE Dev peeps will know it until now, if they are interested ...

throx
11-18-2002, 11:16 AM
From the article linked above,

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs