Hey,all
in Taskmgr.exe, the usename of process svchost.exe,alg.exe can be read. but the following code can't read that. how do i figure out?
_GetUserName proc uses edi hProcess:HANDLE
LOCAL hToken:HANDLE
LOCAL dwBytesRead:DWORD
LOCAL dwBytesRead2:DWORD
LOCAL dwSidType:DWORD
LOCAL pData:DWORD
local szDomainBuffer[256]:BYTE
invoke RtlZeroMemory,offset plUserName,sizeof plUserName
invoke OpenProcessToken, hProcess, TOKEN_QUERY, addr hToken
invoke GetTokenInformation, hToken, TokenUser, NULL, NULL, addr dwBytesRead
invoke GlobalAlloc, GPTR, dwBytesRead
mov pData, eax
invoke GetTokenInformation, hToken,TokenUser, pData, dwBytesRead, addr dwBytesRead
mov edi, pData
invoke LookupAccountSid, NULL, [edi][TOKEN_USER.User.Sid], offset plUserName, \
addr dwBytesRead, addr szDomainBuffer,\
addr dwBytesRead2, addr dwSidType
invoke FreeSid,[edi][TOKEN_USER.User.Sid]
invoke GlobalFree, pData
ret
_GetUserName endp
First of all, there is no error handling, so it's hard to find the error... but after altering the code I posted here (http://www.masm32.com/board/index.php?topic=4868.msg36529#msg36529), I get the following output (shortened).
Current User: Robert
Process ID User Module Name
00000000 --- Process Handle Could Not Be Retrieved ---
Access is denied.
00000004 --- Process Token Could Not Be Retrieved ---
000002C4 SYSTEM smss.exe
00000310 SYSTEM csrss.exe
00000328 SYSTEM winlogon.exe
...
00000408 SYSTEM svchost.exe
Access is denied.
00000460 --- Process Token Could Not Be Retrieved ---
Access is denied.
0000051C --- Process Token Could Not Be Retrieved ---
...
The alterations were just to strip the path from the module names and to add some GetLastError/FormatMessage code after the OpenProcessToken call (formatted errors appear before the line for the corresponding PID). The errors are due to the program not having the required access privilege. I tried adding debug privileges, but that didn't help. I don't know what privilege you need - I will try to find out.
Ossa
hey,Ossa
First of all, Thanks for your answer.
the above code is yours.
i uesed the debug privilege to open the svchost.exe and alg.exe. OFFSET plUserName = NULL,
it should be LOCAL SERVICE and NETWORK SERVICE.
the comrade's code sysview has the same error.
best regards
Quote from: six_L on June 23, 2006, 04:34:41 PM
the above code is yours.
:red should have guessed that... the error checking did expand it quite a bit - but I had it in for cases like this.
Quote from: six_L on June 23, 2006, 04:34:41 PM
i uesed the debug privilege to open the svchost.exe and alg.exe.
Did it work? Sorry - I don't understand what you mean by "OFFSET plUserName = NULL, it should be LOCAL SERVICE and NETWORK SERVICE." - did you mean it still doesn't work? If so, thats what I get.
Anyway on with what I was going to say. What I decided to do was to check privileges of taskmgr.exe whilst it was running to see what
it uses and I get this:
00000B2C Robert taskmgr.exe
Task Manager: Number of Privileges: 20
LUID Access
00000017:00000014 00000000
00000008:00000003 00000000
00000011:00000000 00000000
00000012:00000000 00000000
0000000C:00000000 00000000
00000013:00000000 00000000
00000018:00000000 00000000
00000009:00000000 00000000
00000014:00000000 00000000
00000016:00000000 00000000
0000000B:00000000 00000000
0000000D:00000000 00000000
0000000E:00000000 00000000
0000000A:00000000 00000000
0000000F:00000000 00000000
00000005:00000000 00000000
00000019:00000000 00000000
0000001C:00000000 00000000
0000001E:00000000 00000000
0000001D:00000003 00000000When I use
LookupPrivilegeName on these LUIDs, i get the following error (for all of them - so my code is probably wrong somehow):
QuoteA specified privilege does not exist.
So from here I'm not sure what can be done as I can't find the error in my (very very messy) code,
Ossa
[edit] decided to attach the code in case anyone was interested anyway [/edit]
[attachment deleted by admin]
hey,Ossa
Quotethe above code is yours.
should have guessed that... the error checking did expand it quite a bit - but I had it in for cases like this.
http://www.masm32.com/board/index.php?topic=4868.msg36528#msg36528
ofcourse, your code was modified a bit for my usage.
compared taskmgr.exe, the above code can't work while it reads the username of process svchost.exe,alg.exe.
;-------------------------------------
taskmgr.exe _GetUserName
svchost.exe NETWORK SERVICE
alg.exe LOCAL SERVICE
;-------------------------------------
the plUserName is a buffer that received the username of process.
Six_L,
I don't know in what way your program get process information, but maybe this is what your need:
...
status=NtQuerySystemInformation(SystemProcessInformation,m_pvBuffer,m_cbBuffer,NULL);
...
Hey,KSS
Thanks.
Are you sure that can get process user name?
QuoteNtQuerySystemInformation
[NtQuerySystemInformation may be altered or unavailable in future versions of Windows. Applications should use the alternate functions listed in this topic.]
Retrieves the specified system information.
NTSTATUS WINAPI NtQuerySystemInformation(
SYSTEM_INFORMATION_CLASS SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
Parameters
SystemInformationClass
[in] One of the values enumerated in SYSTEM_INFORMATION_CLASS, which indicate the kind of system information to be retrieved. These include the following values.
SystemBasicInformation
Returns the number of processors in the system in a SYSTEM_BASIC_INFORMATION structure. Use the GetSystemInfo function instead.
SystemPerformanceInformation
Returns an opaque SYSTEM_PERFORMANCE_INFORMATION structure that can be used to generate an unpredictable seed for a random number generator. Use the CryptGenRandom function instead.
SystemTimeOfDayInformation
Returns an opaque SYSTEM_TIMEOFDAY_INFORMATION structure that can be used to generate an unpredictable seed for a random number generator. Use the CryptGenRandom function instead.
SystemProcessInformation
Returns an array of SYSTEM_PROCESS_INFORMATION structures, one for each process running in the system.
These structures contain information about the resource usage of each process, including the number of handles used by the process, the peak page-file usage, and the number of memory pages that the process has allocated.
SystemProcessorPerformanceInformation
Returns an array of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION structures, one for each processor installed in the system.
SystemInterruptInformation
Returns an opaque SYSTEM_INTERRUPT_INFORMATION structure that can be used to generate an unpredictable seed for a random number generator. Use the CryptGenRandom function instead.
SystemExceptionInformation
Returns an opaque SYSTEM_EXCEPTION_INFORMATION structure that can be used to generate an unpredictable seed for a random number generator. Use the CryptGenRandom function instead.
SystemRegistryQuotaInformation
Returns a SYSTEM_REGISTRY_QUOTA_INFORMATION structure.
SystemLookasideInformation
Returns an opaque SYSTEM_LOOKASIDE_INFORMATION structure that can be used to generate an unpredictable seed for a random number generator. Use the CryptGenRandom function instead.
SystemInformation
[in, out] A pointer to a buffer that receives the requested information. The size and structure of this information varies depending on the value of the SystemInformationClass parameter:
SYSTEM_BASIC_INFORMATION
When the SystemInformationClass parameter is SystemBasicInformation, the buffer pointed to by the SystemInformation parameter should be large enough to hold a single SYSTEM_BASIC_INFORMATION structure having the following layout:
typedef struct _SYSTEM_BASIC_INFORMATION {
BYTE Reserved1[24];
PVOID Reserved2[4];
CCHAR NumberOfProcessors;
} SYSTEM_BASIC_INFORMATION;
The NumberOfProcessors member contains the number of processors present in the system. Use GetSystemInfo instead to retrieve this information.
The other members of the structure are reserved for internal use by the operating system.
SYSTEM_PERFORMANCE_INFORMATION
When the SystemInformationClass parameter is SystemPerformanceInformation, the buffer pointed to by the SystemInformation parameter should be large enough to hold an opaque SYSTEM_PERFORMANCE_INFORMATION structure for use in generating an unpredictable seed for a random number generator. For this purpose, the structure has the following layout:
typedef struct _SYSTEM_PERFORMANCE_INFORMATION {
BYTE Reserved1[312];
} SYSTEM_PERFORMANCE_INFORMATION;
Individual members of the structure are reserved for internal use by the operating system.
Use the CryptGenRandom function instead to generate cryptographically random data.
SYSTEM_TIMEOFDAY_INFORMATION
When the SystemInformationClass parameter is SystemTimeOfDayInformation, the buffer pointed to by the SystemInformation parameter should be large enough to hold an opaque SYSTEM_TIMEOFDAY_INFORMATION structure for use in generating an unpredictable seed for a random number generator. For this purpose, the structure has the following layout:
typedef struct _SYSTEM_TIMEOFDAY_INFORMATION {
BYTE Reserved1[48];
} SYSTEM_TIMEOFDAY_INFORMATION;
Individual members of the structure are reserved for internal use by the operating system.
Use the CryptGenRandom function instead to generate cryptographically random data.
SYSTEM_PROCESS_INFORMATION
When the SystemInformationClass parameter is SystemProcessInformation, the buffer pointed to by the SystemInformation parameter should be large enough to hold an array that contains as many SYSTEM_PROCESS_INFORMATION structures as there are processes running in the system. Each structure has the following layout:
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
BYTE Reserved1[48];
PVOID Reserved2[3];
HANDLE UniqueProcessId;
PVOID Reserved3;
ULONG HandleCount;
BYTE Reserved4[4];
PVOID Reserved5[11];
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION;
The NumberOfThreads member contains the total number of currently running threads in the process.
The HandleCount member contains the total number of handles being used by the process in question; use GetProcessHandleCount to retrieve this information instead.
The PeakPagefileUsage member contains the maximum number of bytes of page-file storage used by the process, and the PrivatePageCount member contains the number of memory pages allocated for the use of this process.
You can also retrieve this information using either the GetProcessMemoryInfo function or the Win32_Process class.
The other members of the structure are reserved for internal use by the operating system.
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
When the SystemInformationClass parameter is SystemProcessorPerformanceInformation, the buffer pointed to by the SystemInformation parameter should be large enough to hold an array that contains as many SYSTEM_PROCESS_INFORMATION structures as there are processors (CPUs) installed in the system. Each structure has the following layout:
typedef struct
_SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
LARGE_INTEGER IdleTime;
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER Reserved1[2];
ULONG Reserved2;
} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
The IdleTime member contains the amount of time that the system has been idle, in 100-nanosecond intervals.
The KernelTime member contains the amount of time that the system has spent executing in Kernel mode (including all threads in all processes, on all processors), in 100-nanosecond intervals.
The UserTime member contains the amount of time that the system has spent executing in User mode (including all threads in all processes, on all processors), in 100-nanosecond intervals.
Use GetSystemTimes instead to retrieve this information.
SYSTEM_INTERRUPT_INFORMATION
When the SystemInformationClass parameter is SystemInterruptInformation, the buffer pointed to by the SystemInformation parameter should be large enough to hold an array that contains as many opaque SYSTEM_INTERRUPT_INFORMATION structures as there are processors (CPUs) installed on the system. Each structure, or the array as a whole, can be used to generate an unpredictable seed for a random number generator. For this purpose, the structure has the following layout:
typedef struct _SYSTEM_INTERRUPT_INFORMATION {
BYTE Reserved1[24];
} SYSTEM_INTERRUPT_INFORMATION;
Individual members of the structure are reserved for internal use by the operating system.
Use the CryptGenRandom function instead to generate cryptographically random data.
SYSTEM_EXCEPTION_INFORMATION
When the SystemInformationClass parameter is SystemExceptionInformation, the buffer pointed to by the SystemInformation parameter should be large enough to hold an opaque SYSTEM_EXCEPTION_INFORMATION structure for use in generating an unpredictable seed for a random number generator. For this purpose, the structure has the following layout:
typedef struct _SYSTEM_EXCEPTION_INFORMATION {
BYTE Reserved1[16];
} SYSTEM_EXCEPTION_INFORMATION;
Individual members of the structure are reserved for internal use by the operating system.
Use the CryptGenRandom function instead to generate cryptographically random data.
SYSTEM_REGISTRY_QUOTA_INFORMATION
When the SystemInformationClass parameter is SystemRegistryQuotaInformation, the buffer pointed to by the SystemInformation parameter should be large enough to hold a single SYSTEM_REGISTRY_QUOTA_INFORMATION structure having the following layout:
typedef struct _SYSTEM_REGISTRY_QUOTA_INFORMATION {
ULONG RegistryQuotaAllowed;
ULONG RegistryQuotaUsed;
PVOID Reserved1;
} SYSTEM_REGISTRY_QUOTA_INFORMATION;
The RegistryQuotaAllowed member contains the maximum size, in bytes, that the Registry can attain on this system.
The RegistryQuotaUsed member contains the current size of the Registry, in bytes.
Use GetSystemRegistryQuota instead to retrieve this information.
The other member of the structure is reserved for internal use by the operating system.
SYSTEM_LOOKASIDE_INFORMATION
When the SystemInformationClass parameter is SystemLookasideInformation, the buffer pointed to by the SystemInformation parameter should be large enough to hold an opaque SYSTEM_LOOKASIDE_INFORMATION structure for use in generating an unpredictable seed for a random number generator. For this purpose, the structure has the following layout:
typedef struct _SYSTEM_LOOKASIDE_INFORMATION {
BYTE Reserved1[32];
} SYSTEM_LOOKASIDE_INFORMATION;
Individual members of the structure are reserved for internal use by the operating system.
Use the CryptGenRandom function instead to generate cryptographically random data.
SystemInformationLength
[in] The size of the buffer pointed to by the SystemInformation parameter, in bytes.
ReturnLength
[out, optional] An optional pointer to a location where the function writes the actual size of the information requested. If that size is less than or equal to the SystemInformationLength parameter, the function copies the information into the SystemInformation buffer; otherwise, it returns an NTSTATUS error code and returns in ReturnLength the size of buffer required to receive the requested information.
Return Values
Returns an NTSTATUS success or error code.
The forms and significance of NTSTATUS error codes are listed in the Ntstatus.h header file available in the Windows Device Driver Kit (DDK), and are described in the DDK documentation.
Remarks
The NtQuerySystemInformation function and the structures that it returns are internal to the operating system and subject to change from one release of Windows to another. To maintain the compatibility of your application, it is better to use the alternate functions previously mentioned instead.
If you do use NtQuerySystemInformation, access the function through run-time dynamic linking. This gives your code an opportunity to respond gracefully if the function has been changed or removed from the operating system. Signature changes, however, may not be detectable.
This function has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Ntdll.dll.
i want to know how the taskmgr.exe get it.
Six_L, :red
1. NtQuerySystemInformation()
2. WinStationGetProcessSid()
3. IsValidSid()
4. CachedGetUserFromSid()
Hey,KSS
Thanks.
;======================================================
.text:0100AAC7 mov [ebp-230h], ebx
.text:0100AACD mov [ebp-22Ch], ebx
.text:0100AAD3 lea eax, [ebp-22Ch]
.text:0100AAD9 push eax
.text:0100AADA push ebx
.text:0100AADB push dword ptr [edi+4]
.text:0100AADE push dword ptr [edi]
.text:0100AAE0 mov ecx, esi
.text:0100AAE2 call sub_100A171
.text:0100AAE7 push eax
.text:0100AAE8 push ebx
.text:0100AAE9 call WinStationGetProcessSid
.text:0100AAEE test al, al
.text:0100AAF0 jnz loc_100ABBA
.text:0100AAF6 push dword ptr [ebp-22Ch]
.text:0100AAFC call sub_1002665
.text:0100AB01 pop ecx
.text:0100AB02 mov ebx, eax
.text:0100AB04 mov [ebp-240h], ebx
.text:0100AB0A mov [ebp-230h], ebx
.text:0100AB10 test ebx, ebx
.text:0100AB12 jz short loc_100AB92
.text:0100AB14 lea eax, [ebp-22Ch]
.text:0100AB1A push eax
.text:0100AB1B push ebx
.text:0100AB1C push dword ptr [edi+4]
.text:0100AB1F push dword ptr [edi]
.text:0100AB21 mov ecx, esi
.text:0100AB23 call sub_100A171
.text:0100AB28 push eax
.text:0100AB29 push 0
.text:0100AB2B call WinStationGetProcessSid
.text:0100AB30 test al, al
.text:0100AB32 jz short loc_100AB83
.text:0100AB34 push ebx ; pSid
.text:0100AB35 call ds:IsValidSid
.text:0100AB3B test eax, eax
.text:0100AB3D jz short loc_100AB83
.text:0100AB3F mov dword ptr [ebp-238h], 104h
.text:0100AB49 lea eax, [ebp-238h]
.text:0100AB4F push eax
.text:0100AB50 lea eax, [ebp-224h]
.text:0100AB56 push eax
.text:0100AB57 push ebx
.text:0100AB58 call CachedGetUserFromSid
.text:0100AB5D push 412h
.text:0100AB62 call sub_1002665
.text:0100AB67 pop ecx
.text:0100AB68 mov [ebp-244h], eax
.text:0100AB6E mov [esi+0Ch], eax
.text:0100AB71 test eax, eax
.text:0100AB73 jz short loc_100AB83
.text:0100AB75 lea ecx, [ebp-224h]
.text:0100AB7B push ecx ; lpString2
.text:0100AB7C push eax ; lpString1
.text:0100AB7D call ds:lstrcpyW
.text:0100AB83
;======================================================
Quote from: KSS on June 25, 2006, 11:37:02 PM
2. WinStationGetProcessSid()
3. IsValidSid()
4. CachedGetUserFromSid()
API help?
[attachment deleted by admin]
Platform SDK: Authorization
IsValidSid
The IsValidSid function validates a security identifier (SID) by verifying that the revision number is within a known range, and that the number of subauthorities is less than the maximum.
BOOL IsValidSid(
PSID pSid
);
Parameters
pSid
[in] Pointer to the SID structure to validate. This parameter cannot be NULL.
Return Values
If the SID structure is valid, the return value is nonzero.
If the SID structure is not valid, the return value is zero. There is no extended error information for this function; do not call GetLastError.
Remarks
If pSid is NULL, the application will fail with an access violation.
I know this is an old thread, but it taught be a lot and I feel ike giving back. This is not assembly code, but it is a complete example that illustrates the concepts discussed in this thread. If one of you wants to reimplement or expand on this example, using assembly instead of C, here's some place to start.
If any of this code looks like it came from the "Process Monitor" program by Michel van Kerkhof
http://home.wxs.nl/~wijk0550/ , then you caught me (I did make a few changes). For a more complete application, please refer to Michel's application.
=====================
#include <windows.h>
#include <stdio.h>
#define SystemProcessInformation 5
typedef long NTSTATUS;
typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(int SystemInformationClass,
PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
typedef BOOL (WINAPI *WINSTATIONGETPROCESSSID)(HANDLE hServer, DWORD ProcessId,
FILETIME ProcessStartTime, PBYTE pProcessUserSid, PDWORD dwSidSize);
typedef void (WINAPI *CACHEDGETUSERFROMSID)(PSID pSid , PWCHAR pUserName, PULONG cbUserName);
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
//SystemProcessInformation
typedef struct {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER SpareLi1;
LARGE_INTEGER SpareLi2;
LARGE_INTEGER SpareLi3;
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
LONG BasePriority;
HANDLE UniqueProcessId;
HANDLE InheritedFromUniqueProcessId;
ULONG HandleCount;
ULONG SessionId;
ULONG SpareUl3;
SIZE_T PeakVirtualSize;
SIZE_T VirtualSize;
ULONG PageFaultCount;
ULONG PeakWorkingSetSize;
ULONG WorkingSetSize;
SIZE_T QuotaPeakPagedPoolUsage;
SIZE_T QuotaPagedPoolUsage;
SIZE_T QuotaPeakNonPagedPoolUsage;
SIZE_T QuotaNonPagedPoolUsage;
SIZE_T PagefileUsage;
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER ReadOperationCount;
LARGE_INTEGER WriteOperationCount;
LARGE_INTEGER OtherOperationCount;
LARGE_INTEGER ReadTransferCount;
LARGE_INTEGER WriteTransferCount;
LARGE_INTEGER OtherTransferCount;
} SYSTEM_PROCESS_INFORMATION;
int main(void)
{
int pidCount = 0;
int i;
int nameSize;
wchar_t OwnerName[MAX_PATH];
ULONG reqSize = 0;
ULONG sidSize;
PSID pSid;
HMODULE winsta = NULL;
HMODULE utildll = NULL;
HMODULE ntdll = NULL;
SYSTEM_PROCESS_INFORMATION *procInfo;
WINSTATIONGETPROCESSSID WinStationGetProcessSid;
CACHEDGETUSERFROMSID CachedGetUserFromSid;
NTQUERYSYSTEMINFORMATION NtQuerySystemInformation;
ntdll = LoadLibrary("ntdll.dll");
if (!ntdll)
{
fprintf(stderr, "Could not load ntdll.dll, err = %d\n", GetLastError());
return 1;
}
NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)GetProcAddress(ntdll, "NtQuerySystemInformation");
winsta = LoadLibrary("winsta.dll");
if (!winsta)
{
fprintf(stderr, "Could not load winsta.dll, err = %d\n", GetLastError());
return 1;
}
WinStationGetProcessSid = (WINSTATIONGETPROCESSSID)GetProcAddress(winsta, "WinStationGetProcessSid");
utildll = LoadLibrary("utildll.dll");
if (!winsta)
{
fprintf(stderr, "Could not load utildll.dll, err = %d\n", GetLastError());
return 1;
}
CachedGetUserFromSid = (CACHEDGETUSERFROMSID)GetProcAddress(utildll, "CachedGetUserFromSid");
NtQuerySystemInformation(SystemProcessInformation, NULL, 0, &reqSize);
if ((procInfo = malloc(reqSize)) != NULL)
{
SYSTEM_PROCESS_INFORMATION *p = procInfo;
NtQuerySystemInformation(SystemProcessInformation, procInfo, reqSize, &reqSize);
while (p)
{
if ((DWORD)p->UniqueProcessId == 0)
printf("0 System Idle Process SYSTEM\n");
else
{
sidSize = 0;
nameSize = MAX_PATH;
WinStationGetProcessSid(NULL, (DWORD)p->UniqueProcessId, *((FILETIME *)&p->CreateTime),
(PBYTE)pSid, &sidSize);
if ((pSid = malloc(sidSize)) == NULL)
break;
WinStationGetProcessSid(NULL, (DWORD)p->UniqueProcessId, *((FILETIME *)&p->CreateTime),
(PBYTE)pSid, &sidSize);
CachedGetUserFromSid(pSid, OwnerName, &nameSize);
printf("%d %S %S\n", (DWORD)p->UniqueProcessId, p->ImageName.Buffer, OwnerName);
free(pSid);
}
if (p->NextEntryOffset == 0)
break;
(char *)p += p->NextEntryOffset;
}
free(procInfo);
}
FreeLibrary(utildll);
FreeLibrary(winsta);
FreeLibrary(ntdll);
return 0;
}
====== And here's how to build (with VC6) =======
cl /MD /Zi /Fd pinfo.c /link /debug /incremental:no advapi32.lib kernel32.lib
Have fun,
OC