![]() |
|
|
|
#1
|
|||
|
|||
|
Yes, you can. Use ToolHelp API functions to enum all processes in the system. Check the th32ProcessID field in the PROCESSENTRY32 struct. If it equal with current your process ID, store and remember the th32ParentProcessID field value. Enum again and when the th32ProcessID value equal with saved th32ParentProcessID field value, then the name of parent proces will stored in TCHAR szExeFile[MAX_PATH] field.
This way is same as the way some packers used to detect OllyDbg.exe. If I have time, I will write a OllyDbg plugin to hook and change this way. Regards ! TQN |
|
#2
|
|||
|
|||
|
The same applies to detecting API spy applications and the rest
|
|
#3
|
|||
|
|||
|
Quote:
Here you are! Platform Windows XP. Code:
// get_parent.c - coded by bilbo, 23jul04 - build with "cl -W3 get_parent.c"
// platform: Windows XP
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "advapi32")
#define DebugReadMemory 8
#define FCHK(a) if (!(a)) { printf(#a " failed\n"); exit(0); }
typedef DWORD (NTAPI *PZwSystemDebugControl)(DWORD ControlCode,
PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer,
ULONG OutputBufferLength, PULONG ReturnLength);
PZwSystemDebugControl ZwSystemDebugControl;
DWORD pSystemProc;
struct mem {
PVOID kernel_addr;
PVOID user_addr;
DWORD len;
};
void
EnablePrivilege(LPCSTR lpszName)
{
HANDLE hToken;
TOKEN_PRIVILEGES tok;
FCHK(OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken));
tok.PrivilegeCount = 1;
tok.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
FCHK(LookupPrivilegeValue(NULL, lpszName, &tok.Privileges[0].Luid));
FCHK(AdjustTokenPrivileges(hToken, FALSE, &tok, sizeof(tok), NULL, NULL));
}
/*
* read one long from kernel space
*/
DWORD
rd(DWORD addr)
{
struct mem mem;
DWORD m;
mem.kernel_addr = (PVOID)addr;
mem.user_addr = &m;
mem.len = 4;
FCHK(!ZwSystemDebugControl(DebugReadMemory, &mem, sizeof(mem), 0, 0, 0));
return m;
}
void
rdstr(DWORD addr, LPSTR buf, int buflen)
{
int i;
struct mem mem;
mem.kernel_addr = (PVOID)addr;
mem.user_addr = buf;
mem.len = 1;
for (i=0; i<buflen; i++) {
FCHK(!ZwSystemDebugControl(DebugReadMemory, &mem, sizeof(mem), 0,0,0));
if (!*buf++) break;
addr++;
// reassign structure mem
mem.kernel_addr = (PVOID)addr;
mem.user_addr = buf;
}
}
void
prepare_me(void)
{
HMODULE hModule;
// get the API address
FCHK(hModule = GetModuleHandle("ntdll.dll"));
FCHK((ZwSystemDebugControl = (PZwSystemDebugControl)
GetProcAddress(hModule, "ZwSystemDebugControl")));
EnablePrivilege(SE_DEBUG_NAME);
}
void
main(void)
{
DWORD eprocess, mypid, parentpid, tmppid;
char myname[17]={0}, parentname[17]={0};
prepare_me();
// get current EPROCESS from kernel space
eprocess = rd(0xFFDFF000+0x124); // KPRCB.KTHREAD
eprocess = rd(eprocess+0x44); // KTHREAD.KAPC_STATE.KPROCESS
// get pids from kernel space
mypid = rd(eprocess+0x84); // EPROCESS.UniqueProcessId
parentpid = rd(eprocess+0x14C); // EPROCESS.InheritedFromUniqueProcessId
// get my name from current EPROCESS
rdstr(eprocess+0x174, myname, 16); // EPROCESS.ImageFileName
// scan back process list to find parent EPROCESS
//printf("%x %d\n", eprocess, mypid);
eprocess = rd(eprocess+0x8C); // ActiveProcessLinks
while (1) {
tmppid = rd(eprocess+(0x84-0x88)); // UniqueProcessId
//printf("%x %d\n", eprocess, tmppid);
if (tmppid == parentpid) break;
eprocess = rd(eprocess+(0x8c-0x88)); // Blink
}
// get parent name from parent EPROCESS
rdstr(eprocess+(0x174-0x88), parentname, 16); // EPROCESS.ImageFileName
printf("mypid: %d(%.16s), parentpid: %d(%.16s)\n",
mypid, myname, parentpid, parentname);
}
|
|
#4
|
|||
|
|||
|
Thank for your code, bilbo !
I compiled your code, run on my Win 2000 Test Server. The call ZwSystemDebugControl failed, return STATUS_INVALID_INFO_CLASS (0xc0000003). Can you explain me the meaning of "#define DebugReadMemory 8". In the book "The Win2000 Native API Reference", we only have: typedef enum _DEBUG_CONTROL_CODE { DebugGetTraceInformation = 1, DebugSetInternalBreakpoint, DebugSetSpecialCall, DebugClearSpecialCalls, DebugQuerySpecialCalls, DebugDbgBreakPoint // maximize is 6 } DEBUG_CONTROL_CODE; If I remember correctly, Kayaker have posted a method to detect parent process and number of threads uses native API in a topic on Woodmann.net. I will search again now. Attached file is my source code and .exe of DetectOlly app, uses ToolHelp API. Regards ! TQN Last edited by TQN; 07-24-2004 at 15:55. |
|
#5
|
|||
|
|||
|
I compiled the exact code in an empty Win32 Console project running Windows XP compiled 0 errors 0 warnings. Ran without error, the results were:
mypid: 880(lsass.exe), parentpid: 824(winlogon.exe) Press any key to continue The only documentation on the structure I could find was typedef enum _DEBUG_CONTROL_CODE { DebugSysReadIoSpace = 14, DebugSysWriteIoSpace = 15, DebugSysReadMsr = 16, DebugSysWriteMsr = 17, DebugSysReadBusData = 18, DebugSysWriteBusData = 19, } DEBUG_CONTROL_CODE; Perhaps its a windows xp/2000 difference |
|
#6
|
|||
|
|||
|
Hi Viasek !
Something wrong here. I agree with you that the code will run well on WinXP. But the parent process display is not correct. If your app is a Win32 Console app, the parent process must be Cmd.exe if you run your app from console or Explorer.exe if you run your app from Explorer. We can use the tool Process Explorer of SysInternals to check this. Regards ! TQN |
|
#7
|
|||
|
|||
|
From the command prompt:
Code:
C:\project\ParentID\Debug>parentid.exe mypid: 880(lsass.exe), parentpid: 824(winlogon.exe) C:\project\ParentID\Debug>parentid.exe mypid: 1492(ParentID.exe), parentpid: 284(cmd.exe) C:\project\ParentID\Debug>parentid.exe mypid: 716(ParentID.exe), parentpid: 284(cmd.exe) C:\project\ParentID\Debug>parentid.exe mypid: 384(ParentID.exe), parentpid: 284(cmd.exe) --Reopened Cmd prompt-- C:\project\ParentID\Debug>parentid mypid: 800(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 620(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 948(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1116(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1152(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1132(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1120(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 632(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 944(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1272(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 224(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1188(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1308(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1276(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1304(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 276(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1424(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1160(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1452(ParentID.exe), parentpid: 696(cmd.exe) C:project\ParentID\Debug>parentid mypid: 928(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1220(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 220(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1952(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 520(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 516(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1492(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 740(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 780(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 572(ParentID.exe), parentpid: 696(cmd.exe) C:\project\ParentID\Debug>parentid mypid: 1472(ParentID.exe), parentpid: 696(cmd.exe) Code:
mypid: 1416(ParentID.exe), parentpid: 1360(vcspawn.exe) Press any key to continue mypid: 624(devenv.exe), parentpid: 1748(explorer.exe) Press any key to continue mypid: 440(ParentID.exe), parentpid: 196(vcspawn.exe) Press any key to continue mypid: 624(devenv.exe), parentpid: 1748(explorer.exe) Press any key to continue mypid: 624(devenv.exe), parentpid: 1748(explorer.exe) Press any key to continue mypid: 1276(ParentID.exe), parentpid: 1308(vcspawn.exe) Press any key to continue mypid: 1188(ParentID.exe), parentpid: 224(vcspawn.exe) Press any key to continue |
|
#8
|
|||
|
|||
|
Viasek is right: the argument DebugReadMemory (8) has been added in Windows XP platform and it is not documented. Also arguments 14-19, pointed out by Viasek, have been added in Windows XP.
If you are interested in Win2k platform, you need another way to read kernel space (driver or callgate). The "something wrong" is very interesting: I strangely cannot recreate it on my platform (Windows XP SP1), neither from Win32 console nor from Visual Studio. It is related to the way the current process id is inferred, not to the way used to retrieve the process name or the process parent! It looks like, at the moment in which the current process structure is read from kernel, the scheduler has selected another process... To avoid this, you can simply retrieve the current process id from userland: Code:
mypid = 0x7FFDE020; // &(TEB.CLIENT_ID.UniqueProcess)
mypid = *(LPDWORD)mypid;
P.S. This is my last post in this thread. I'm afraid JMI call me an FTP chaser! |
![]() |
| Thread Tools | |
| Display Modes | |
|
|