Page 4 of 6 FirstFirst ... 23456 LastLast
Results 46 to 60 of 81

Thread: Question about stealth methods

  1. #46
    Registered User
    Join Date
    Nov 2002
    Posts
    6

    This should help

    Hey, Lost...

    Nice job with what you're doing. I think this is heading in the right direction.

    I thought I'd drop this lil tidbit to you, as I think it could be useful. Basically, it's an undocumented feature of the ObReferenceObjectByHandle function to return the address of an EPROCESS block when you pass in a process id.

    Take a look here for details:

    http://www.ntdev.org/archive/ntdev9908/msg0108.html

    The user level process can enum all processes then call a driver IOCTL with the target process id and memory address as the parameters.

    Fez Ajer

    EDIT: Ok, this wants a PROCESS HANDLE instead of a PROCESS ID... Back to the reference
    Last edited by fez_ajer; 12-15-2002 at 03:55 AM.

  2. #47
    Registered User
    Join Date
    Oct 2002
    Posts
    59
    fez_ajer, that is interesting function, but has one major drawback:

    - I need to obtain process handle before using function, so that means I need to use OpenProcess in User mode for example . And that is very same thing that we are trying to avoid with kernel driver

    But it could be possibly used safely in following way:

    1) i get my keysniffer.EXE process Handle (exe name is just example, this is program that use kernel driver to read key, and then send it to SEQ)
    2) I use that handle in ObReferenceObjectByHandle to get EPROCESS address of keysniffer.exe
    3) now, I have valid pointer to ONE EPROCESS struct, and I can walk whole EPROCESS same way as in myFindProcess

    So, what would be benefit? I wouldn't need to hardcode address of PsActiveProcessHead, which is good thing, since any hardcoding fixed numbers is HIGLY OS-version specific, and may need to be updated even for OS service pack, and surely for new OS version ( ie. I didnt try it on win XP SP1 )

    What is drawback? I would still need to hardcode offset of List pointers and Process name within EPROCESS . This is not exactly 'drawback' of using ObReferenceObjectByHandle , but since offsets change with new OS version same way as PsActiveProcessHead does, any benefit would be lost -> new OS version would need added new 'case BuildNumber == xxx' anyway.

    Conclusion:
    - previous solution works for win2k and XP (maybe for NT4.0, but that is totaly unimportant since no one is playing EQ on NT40 without DX support).
    - New OS version would need function to be upgraded, but that will be easy. And so far I dont have version independent solution.
    - this solution provide me with all functionality that i needed from kernel driver: undetectable reading of part of memory from given process name and address
    - as of my latest post (with FindProcess in kernel), I consider driver as finished - I can think of nothing new to add to it that would help increase security for keyreader.


    Of course, I will accept any good suggestion for improvement. At this moment I see possible improvements in technical details (like making more OS independent solution) and not in main functionality ( like making more secure and indetectable memory read ).
    Last edited by lostinspace; 12-16-2002 at 11:29 AM.

  3. #48
    Registered User
    Join Date
    Nov 2002
    Posts
    6

    If you just need any EPROCESS struct

    I believe there is a kernel function:

    KeGetCurrentProcess()

    which returns PEPROCESS for the process which calls the IOCTL. That should indeed do the trick to avoid hardcoding the list head. You'd still need to hardcode the offsets of the list pointers, so you don't really gain that much.

    As for ObReferenceObjectByHandle, I posted that because I was lead to believe it worked by passing in a PROCESS ID as opposed to a PROCESS HANDLE. When I noticed the distinction I edited my post.

  4. #49
    Registered User
    Join Date
    Nov 2002
    Posts
    36
    Having trouble implmenting myGetPA() and myReadPA() routines. Could you post examples please. What a spounge I am.

  5. #50
    Registered User
    Join Date
    Dec 2001
    Posts
    752
    lostinspace wrote:

    and may need to be updated even for OS service pack, and surely for new OS version ( ie. I didnt try it on win XP SP1 )
    I am trying to get it work on xp sp1 - will post wether it works
    -- Lord Crush

    Greater Faydark has to be cleaned from all Elves !

    This is a HOTKEY !!!

  6. #51
    Registered User
    Join Date
    Oct 2002
    Posts
    59
    fez_ajer, that was good hint

    While function KeGetCurrentProcess does not exists, there is one named PsGetCurrentProcess. I just used result of that function in myFindProcess to determine PsActiveProcessHead .

    New code to determine offsets looks like:

    BuildNumber= (*NtBuildNumber) & 0x0000FFFF;

    if ((BuildNumber==0x421) || (BuildNumber==0x565) ) { // NT 3.51; 4.0
    ListEntryOffset=0x98;
    NameOffset=0x1DC;
    } else if (BuildNumber==0x755) {// Windows 2000
    ListEntryOffset=0xA0;
    NameOffset=0x1FC;
    } else {// treat anything else as Windows XP, BuildNumber==0xA28
    ListEntryOffset=0x88;
    NameOffset=0x174;
    }

    PsActiveProcessHead = (PLIST_ENTRY)(((char*) PsGetCurrentProcess() )+ListEntryOffset);


    gawker, myGetPA and myReadPA should be same functionality as already existing case #10 and #13 parts, but anyway, here is code:


    // my custom GetPhysicalAddress from Virtual Address
    DWORD32 myGetPA(DWORD32 vAdr){
    PDWORD32 p32bit;
    if ((vAdr<0xA0000000)&&(vAdr >= 0x80000000)){
    // here is 4MB paged kernel range. I dont need it, but ...
    return vAdr & 0x1FFFFFFF;
    }else {
    // here is part for 4kb pages, find PTE starting at 0xC0000000 + ...
    p32bit= (PDWORD32) ( 0xC0000000 + ( 4*(vAdr >> 12)) ) ;
    // check if PTE is accessible
    if (!MmIsAddressValid(p32bit)) return 0;
    // last bits are retained from virt. addr
    return (*p32bit & 0xFFFFF000) | (vAdr & 0xFFF);
    }
    }


    // my Read from PhysicalAddress
    DWORD64 myReadPA(DWORD32 inAdr){
    PDWORD64 p64bit;
    DWORD64 nOut=0;
    PHYSICAL_ADDRESS pa;
    if (inAdr==0) return 0;
    pa.QuadPart = inAdr;
    p64bit= MmMapIoSpace( pa, 8, MmNonCached );
    if (p64bit==NULL) return 0;
    nOut= *p64bit;
    MmUnmapIoSpace( p64bit, 8);
    return nOut;
    }

  7. #52
    Registered User
    Join Date
    Nov 2002
    Posts
    6

    Here's an interesting function...

    Lost,

    I think that KeGetCurrentProcess *MAY* be an undocumented export. I also know that this function:

    PsLookupProcessByProcessId(IN ULONG ulProcId,OUT struct _EPROCESS ** pEProcess);

    Is definitely undocumented. You can find some info on it here:

    http://www.beyondlogic.org/porttalk/porttalk.htm

    and it is also exported by the public version of NTIFS.H which is maintained at:

    http://www.acc.umu.se/~bosse/

    Cheers and good luck

    - Fez

  8. #53
    Registered User
    Join Date
    Dec 2001
    Posts
    752
    fez_ajer,

    i found a nice proggy for installing the driver

    http://www.beyondlogic.org/dddtools/dddtools.htm

    http://www.beyondlogic.org/dddtools/installer.zip

    - i have not tested it yet

    Ty
    -- Lord Crush

    Greater Faydark has to be cleaned from all Elves !

    This is a HOTKEY !!!

  9. #54
    Registered User
    Join Date
    Nov 2002
    Posts
    6

    Ok, here's the jig...

    I've implemented an IOCTL function which uses nothing but win32 kernel calls to read the memory. This means no hardcoding of list pointers and such. It also means it should work without modification for all the NT based platforms.

    The idea is you have your usermode program enumerate the processes then call the IOCTL passing in the PROCESS ID and OFFSET of the memory you want to read.

    The code uses just one undocumented function, PsLookupProcessByProcessId, but as I mentioned it's properly handled by the free version of NTIFS.H. (see above)

    Here's the code snippet:

    // Get a pointer to the requested process EPROCESS block
    if ((ntStatus = PsLookupProcessByProcessId(request->procid, &pEProc)) == STATUS_SUCCESS)
    {
    // Attach to the target process memory space
    KeAttachProcess(pEProc);

    // Assume we're going to fail
    ntStatus = STATUS_INVALID_PARAMETER;

    // Is the requested virtual address valid?
    if (MmIsAddressValid(request->offset))
    {
    // Point to the key value physical address
    pPhysAddress = MmGetPhysicalAddress(request->offset);

    // Map the address space
    pKeyVal = MmMapIoSpace(pPhysAddress, 8, MmNonCached);

    // Put the lime in the coconut
    request->memval = *pKeyVal;

    // Unmap the address space
    MmUnmapIoSpace(pKeyVal, 8);

    // Tell them they have mail
    Irp->IoStatus.Information = sizeof(REQUEST);

    // We actually succeeded!
    ntStatus = STATUS_SUCCESS;
    }

    // Detach from the process memory space
    KeDetachProcess();
    }


    Fez
    Last edited by fez_ajer; 12-18-2002 at 03:21 AM.

  10. #55
    Registered User
    Join Date
    Oct 2002
    Posts
    59
    Yep, after first post about PsLookupProcessByProcessId, I added new function call (#17) to my driver where as parameters i expect process ID and Offset, and after obtaining EPROCESS, remaining is same as in #16.

    But I still use previous function, #16, because I consider it harder to detect. Namely, PsLookupProcessByProcessId has following potential risks:

    - PsLookupProcessByProcessId adds another function which, if hooked, would undeniably show that someone is tempering with EQ (that is, function has as parameter process ID of EQ)

    - both #16 and #17 has function KeAttachProcess that, if somehow hooked, would show that someone is tempering with EQ (again, has eprocess of EQ as parameter). But this function is probably called far more frequently than PsLookupProcessByProcessId

    - necessary enumeration function in user mode , if hooked, is not positive proof for sniffer, but still can add user mode application to 'suspect list'

    Now, I know that 'hooking' on kernel functions is very hard to implement, so solution that fez_ajer posted is quite good and quite secure. I guess same reason that initiated me to write kernel driver is also reason why I still use myFindProcess - I want solution that has best probability to be undetected.

    On a side note, kernel function MmGetPhysicalAddress will not work if adress is VirtualProtected. That is reason for my custom GetPhysicalAddress function.

  11. #56
    Registered User
    Join Date
    Nov 2002
    Posts
    6

    Are you sure about MmGetPhysicalAddress?

    Hrm... I've never actually checked but I would think that MmMapIoSpace would fail on virtual protect rather than MmGetPhysicalAddress... The reasons being:

    1) MmGetPhysicalAddress supposedly just converts a virtual address into a physical address given the context of a process. That can be done even if it is protected because it needs to be mapped for access. It would make more sense to tell you where something is before telling you that you can't get there.

    2) MmMapIoSpace returns a PVOID vs. a PHYSICAL_ADDRESS for MmGetPhysicalAddress. The PVOID can be null on failure whereas I don't think PHYSICAL_ADDRESS is equivalent to a pointer.

    Not that I would expect anything in this M$ API to make logical sense though

    It just seems funny to me that Microsoft would protect something by just not letting you figure out where it is and then allowing you to call a MmMapIoSpace on it regardless of privilege as long as you could find it yourself.

  12. #57
    Registered User
    Join Date
    Oct 2002
    Posts
    59
    Hehe ... well, I also did not expect any consistency from M$ API, so I tested all those combinations with my own program simulating eqgame. Namely, I generated 8 byte key in that program and then tested several options:

    - key at fixed offset (like it is now in EQ)
    - only pointer to key is fixed, key itself at random offset (GlobalAlloc)
    - pointer to key is fixed, and key is at random offset (VirtualAlloc) and protected by VirtualProtect


    As it can be seen in my previous posts, if key is VirtualProtected, it has following effect on kernel driver:

    - can be read with normal memory read, will not trigger trap, but will fail read
    - can be read any time with MapIoSpace reading physical memory ... i think that it is logical after all, since you VirtualProtect virtual address , and in MapIoSpace you use completely diferent physical address
    - can not obtain physical address with MmGetPhysicalAddress if protected ... this also seems to be logical, since this function use virtual address as parameter, and process is protecting that virtual address


    Again, to overcome that obstacle, I wrote my own GetPhysicalAddress, and everything works ok on my test aplication - I can read both protected and unprotected memory any time, without triggering anything.

    Another reason why MapIoSpace works fine is fact that virtual memory is protected on process basis. Meaning , if one process is protecting 0x450000, same address can be safely read on other process. Information about VirtualProtect is actually handled by processor itself, and it is in PTEs, or virtual memory paging entries - area from 0xc0000000 where for each 4kb (or 4MB) of virtual memory there is one 32bit (4 byte) PTE pointing at physical memory address. Since least granularity is 4kb ( 0x1000), lower 3 hex digits (12 bits) are not needed for physical address - and that is place where processor store information about that virtual page: is it in memory at all, or at disk; is it read only or r/w or..; is it protected or not; etc...

    And considering that mmGetPhysicalAddress actually only read that PTE and return result, it was logical and only spot to put control of VirtualProtection from Windows point of view - considering that actual trap triggering is done by processor itself.

    I even wrote my own setVirtualProtect and readVirtualProtect that just write specific bits in PTE for given memory. Those are missing function numbers in my case example if you wondered: #14 and #15
    Last edited by lostinspace; 12-18-2002 at 12:56 PM.

  13. #58
    Registered User
    Join Date
    Nov 2002
    Posts
    6

    Now that you say it that way...

    It makes much more sense as to WHY

    It just doesn't really offer any real protection. That's good for our case, but suxxor for the OS itself.

    Fez

  14. #59
    Registered User
    Join Date
    Nov 2002
    Posts
    22

    Nice Job

    Nice job LostInSpace - this was the concept I was describing in my earlier post.

    It has taken some time - but in the end this solution will prove to be totally immune to detection. It might still suffer from efforts by SOE to obfuscate the key - but those can be picked off as they occur.

    The memory management registers are manipulated a lot more than most people know. It is not uncommon for "Watchpoints" in a debuggers to tweak them to make it easier and more efficient to perform their task.

    As to the worry about intrusion and OS safety. The key issue is the means by which these hooks/kernel mode programs can be run. I have been a bit surprised that they go in so easy. It seems like there should be more protection against allowing them to be inserted into the OS, or does everyone always run all their stuff from max privilege mode?

    Somewhere on another post - it seems that people were investigating whether EQ can be run with less privileges. Not sure what they finally concluded. But it brings up an interesting thought. Why in the heck does a game need access to the kernel?

    Why should they presume to attach to the OS and do who knows what to our computer?

    I suspect someplace in SOE a lawyer is asking an enthusiastic bunch of zealots why in the heck they want to do something so intrusive to the computers of their customers. The legal riskls are enormous.

    They install some piece of code - and accidentally Quicken fires off a Checkpoint transaction that empties my bank account (ok - far fetched) - think I won't be looking for recourse? And don't tell me about EULA terms and conditions - those are meaningless until tested in a court - something SOE certainly does not want to do.

    I doubt SOE will ever hook the OS. Too much to lose.

    Having said that - I would be interested in a posted copy of the final version of the driver. I like looking at the solution - it gives me ideas for other uses.

    Finally - does your approach do the Virtual-to-Physical conversion every time it gets a key? There really is no guarantee that the page with the key in it is in memory - or even in the same physical location from call to call?

    Last edited by wiz60; 12-19-2002 at 07:00 AM.
    Wiz60
    The Lurker at the Threshold

  15. #60
    Registered User
    Join Date
    Aug 2002
    Posts
    143
    They install some piece of code - and accidentally Quicken fires off a Checkpoint transaction that empties my bank account (ok - far fetched) - think I won't be looking for recourse? And don't tell me about EULA terms and conditions - those are meaningless until tested in a court - something SOE certainly does not want to do.
    Running under Win9x you can do that anyway with just a stray pointer. I don't see any greater legal risk there than there would be from simply allowing a game to run under Win9x.

    If you think about the things a virus protection program or home firewall could potentially do (both hook kernel drivers) then something that hooks a few APIs is tame in comparison.

    I seriously doubt SOE would ever bother with the effort required to detect lostinspace's sniffer. They'd pretty much have to scan the driver list and check each one's code space looking for a signature. Very, very unlikely and way too much effort. I'd expect something simpler like more obfuscation of the key and potentially encrypting eqgame.exe so a simply debug dump of it isn't so easy.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

You may post new threads
You may post replies
You may post attachments
You may edit your posts
HTML code is Off
vB code is On
Smilies are On
[IMG] code is Off