Log in

View Full Version : Thread Based Code/behavior Profiler


BanMe
May 14th, 2009, 22:20
The object of this discussion is how to best profile Thread.

I think the best way to profile a Thread is Hook _BaseThreadStartThunk and _BaseProcessStartThunk(for main thread) but to do this I need to load before any other program code executes other then the loading of ntdll and kernel32..and most definitly before user32 loads.. im doing this for securitty reasons but am still stuck on how to do it without kernel mode..

but anyway back to profiling i want to eventually be able to analyze program behavior before it is executing and also while it is executing, i also wish make changes to memory if the program isnt doing what we want, but in a dynamic way with little input from the user.

I'm going to lay out the information that I would like to gather from threads to create a thread profile.

Start Address
End Address
Code Size
Number Of Calls Made
Number of Conditionals jumps
(maybe) List of API's called on each control path..




For the first 3 we can use hooks on BaseProcessStartThunk and BaseThreadStartThunk and GetFunctionLength, also can use this method to get the number of conditional jumps and with slight modification we can search for the call opcode as well using GetFunctionLength with modifications..

Here is a list a very easily obtainable information that will supplement the above information.

ProcessName
ProcessID
ThreadID

alternitivly instead of using GetFunctionLength within the hook so extensivly we could could fire up a LPC Connection to communicate the code chunk out of the process for analysis within the hooks.

these solution aren't vista freindly nor are they 64 bit compatible as of yet.. but that is all the fun of making something nowadays, i think.

All suggestions and are welcome in gathering this data, whether practical or not.

Kayaker
May 15th, 2009, 17:38
I'm sure you've already considered this, but PsSetCreateThreadNotifyRoutine, possibly in combination with PsSetCreateProcessNotifyRoutine to isolate a particular process, wouldn't work? As long as ETHREAD.Win32StartAddress/StartAddress is valid at the time of notification, you should have all you need for the profiling?

You should be able to suspend the thread within the notification routine if desired. You can communicate with your usermode app using an APC through an already established alerted UM thread and signal the notification routine when you're ready to resume the thread.

There is the issue with other threads queueing for the notification routine. You may be able to either filter them from being suspended, or, you may not have to worry about it. In mucking around with PsLoadImageNotifyRoutine in such a manner, I found that no race condition occurred, any loading drivers simply waited (somewhere in the execution path) until the suspended notification routine was resumed.

BanMe
May 15th, 2009, 19:35
thank you kayaker for your excellent reply, and yes i have considered kernel mode solutions to this problem..but would
ETHREAD.Win32StartAddress/StartAddress point to _BaseThreadStartRoutine or does it point to the real start address..
I evntually plan to implement a Driver, but that is far down the road when all my code is "Native" and the analysis code is win32 API free..(easy transition to kernel mode xD)

My plan is to implement a Native Application that analyze's the code and exports the results and along with the modifications to a Shared Section which is then viewable from a user mode program..maybe CsrssWalker will have a home in the Native Application that will move it from POC to workable code..

I have no plans on implementing this in Vista or 64 bit XP, I only want to make it for 2000 and XP 32 bit.

I will post my Hook routine in order to shed more light on what I'm planning on doing.

Kayaker
May 15th, 2009, 21:31
Doing a quick check in Softice:

Code:
WinXP ETHREAD structure
+0x220 ThreadsProcess : Ptr32 to
+0x224 StartAddress : Ptr32 to
+0x228 Win32StartAddress : Ptr32 to
+0x228 LpcReceivedMessageId : Uint4B



ETHREAD.ThreadsProcess points to EPROCESS block

For the main thread, ETHREAD.StartAddress points to kernel32!BaseProcessStartThunk
For any secondary threads, ETHREAD.StartAddress points to kernel32!BaseThreadStartThunk


ETHREAD.Win32StartAddress points to thread start. though by definition it's a union field with LpcReceivedMessageId.


I noticed in some multithreaded processes that the value of Win32StartAddress in the non-main thread might be 0 (non-gui thread?) or point to a thread starting address in another module (ntdll!RtlpWorkerThread, ntdll!RtlpTimerThread, advapi32!ScSvcctrlThreadW, rpcrt4, msvcrt..)

darawk
May 16th, 2009, 01:19
A simplistic and somewhat incomplete method would be to inject a dll into every running process and hook CreateProcessExA/W and CreateProcessAsUser(this is in user32.dll and creates a process without going through the normal call chain IIRC), switch up the flags to CREATE_SUSPENDED, inject your code into it, then start the process. This is incomplete in the sense that processes started from kernel-mode won't be caught, but any user-initiated process would be, and this would certainly work to profile the majority of applications.

BanMe
May 16th, 2009, 04:36
yes that is a very barebone method of doing it.

my plan is to run side by side the win32 environment with a Native applicication placed as a subsystem like win32 posix ect.. this subsystem will directly or dynamically modify system dll's on the disk.(2000,xp..fuck vista...for now..)..this done without injection.. hopefully i can coax the Win32 subsystem to load me right after ntdll or kernel32 in all process's(..hook LdrpCheckForLoadedDll directly). so this substem waits for LPC Connections which are made each time BaseProcessStartThunk or BaseThreadStartThunk is called. These Connection communicate a variety of messages but the most important job is that it will communicate code chunks(separated by there control codes) there jumps.. and as darawk has made a lil function called GetFunctionLength that is simple and elegant and has so many uses, one of which is identifying and separating code chunks based on there branching ability..(btw thank you for that work darawk very nice.) another use comes with slight modification can be used to dig out call address's (ie Modules and API names) by finding the call opcode instead of finding the "jmp opcodes" this can be done fairly quickly..and then comes behavior recognition based on code analysis before execution of code...and then come the whole GUI that makes viewable and most importantly instantly usable..all this data...

as of now im almost done with the basic native "server" application and subsystem (Multi-connect, working on Message receiving) I am currently taking in ideas that will benefit my symbiotic attachment scheme..

oh and thanks you to the both of you, your suggestions are most appreciated (helps me think ),
kind regards BanMe

disavowed
May 16th, 2009, 17:19
in case you use darawk's approach, i strongly suggest hooking CreateProcessInternal instead of CreateProcessEx or CreateProcessAsUser. see http://a-twisted-world.blogspot.com/2008/03/createprocessinternal-function.html and http://www.reactos.org/generated/doxygen/dc/de3/dll_2win32_2kernel32_2process_2procsup_8c.html#fee2bf936652363104809af4473c7a66 for a little more info.

BanMe
May 17th, 2009, 22:02
yea, the only problem with that is that hooking CreateProcess(x) will only yield limited information about the threads running or going to run in that Process... and maybe if i hook CsrNewThread and ZwSetInformationThread in Ntdll, I can avoid kernel32 hooks altogether and therefore load after ntdll and not after kernel32.. the reason why i want Early Runtime Loading is to get the KiSystemServiceDescriptorTable/KiSystemServiceDescriptorTableShadow..if i load before user32 then all running threads should direct me to the SSDT address(using NtSystemDegugControl and reading Current EThread.ServiceTable),also after user32 loads I can use the same method and it will point to SSDT Shadow now. im using these addresses to virgin check these tables.. and dynamically generate counter measure code(that in late future) by registering a new service with the hooked service's old SSDT indexed address and modifying the Ntdll index number to call the bypassed function..thats far down the road.. and thank you disavowed for the links and your input, it is appreciated.many more things to work out and to discuss.

If any of you want to talk directly my msn account is rinna_marlen |a_t| hotmail.com.
Regards BanMe

Kayaker
May 18th, 2009, 00:41
There is another option you might consider. As can be seen from the CreateProcessInternal definition, Windows informs the CSRSS subsystem of a process being created through CsrClientCallServer (via BasepNotifyCsrOfCreation) and the LPC message system.

CsrClientCallServer messages are also used with MANY other API's, including CreateThread, CreateRemoteThread, ExitProcess, etc., as well as several of the Console API's.

The path is CsrClientCallServer -> NtRequestWaitReplyPort. The latter can be SSDT hooked as ZwRequestWaitReplyPort with all the advantages of kernel mode, though I suppose it could be done at the ntdll level as well. Individual LPC messages can be filtered based on an ApiNumber.


Here is the ReactOS definition of CsrClientCallServer:

Code:

NTSTATUS STDCALL CsrClientCallServer(PCSR_API_MESSAGE Request,
PVOID CapturedBuffer OPTIONAL,
CSR_API_NUMBER ApiNumber,
ULONG RequestLength)


Disassemble kernel32 and find the XREFS for CsrClientCallServer and you will find the various ApiNumbers, i.e.

Code:

// Selected CSR Api Numbers used with CsrClientCallServer

#define BasepCreateProcess 0x10000 // CreateProcessInternalW
#define BasepCreateThread 0x10001 // CreateThread / CreateRemoteThread
#define BasepGetTempFile 0x10002 // GetTempFileNameW
#define BasepExitProcess 0x10003 // ExitProcess

// Win2K only
#define BasepDebugProcess 0x10004 // DebugActiveProcess

#define BasepSetProcessShutdownParam 0x1000C // SetProcessShutdownParameters
#define BasepGetProcessShutdownParam 0x1000D // GetProcessShutdownParameters

// The following two ApiNumbers are used with the internal function _CsrBasepNlsGetUserInfo
// _CsrBasepNlsGetUserInfo is called by other functions, but for our interests the
// path is part of the general Process creation and loading routine:
// ??? -> _NlsDllInitialize@12 -> _NlsProcessInitialize@0 -> _CsrBasepNlsGetUserInfo

// The values are different for Win2K and XP

#define BasepNlsGetUserInfo_2K 0x1001A // _CsrBasepNlsGetUserInfo (Win2K)
#define BasepNlsGetUserInfo_XP 0x1001E // _CsrBasepNlsGetUserInfo (XP)

#define BasepSetClientTimeZoneInformation 0x1001A // SetClientTimeZoneInformation (XP)

#define ConsolepOpenConsole 0x20200 // OpenConsoleW
#define ConsolepReadConsoleInput 0x20201 // ReadConsoleInputA
#define ConsolepWriteConsoleInput 0x20202 // WriteConsoleInputA
#define ConsolepReadConsoleOutput 0x20203 // ReadConsoleOutputA
#define ConsolepWriteConsoleOutput 0x20204 // WriteConsoleOutputA
#define ConsolepReadConsoleOutputString 0x20205 // ReadConsoleOutputCharacterA
#define ConsolepWriteConsoleOutputString 0x20206 // WriteConsoleOutputCharacterA

#define ConsolepReadConsole 0x2021D // ReadConsoleA
#define ConsolepWriteConsole 0x2021E // WriteConsoleA

#define ConsolepVerifyIoHandle 0x20223 // VerifyConsoleIoHandle
#define ConsolepAlloc 0x20251 // AllocConsole



The CSR_API_MESSAGE structure is made up of a fixed length Header and a variable length Data section. This is the definition I used for my project:

Code:

// Main structure defining the type of LPC messages
// processed by CsrClientCallServer -> NtRequestWaitReplyPort

typedef struct _CSR_API_MESSAGE
{
LPC_MESSAGE_HEADER Header;

struct
{

ULONG Reserved;
ULONG ApiNumber; // CSR_API_NUMBER

union
{

CSRSS_CREATE_PROCESS_LPCMESSAGE CreateProcessRequest; // 0x10000
CSRSS_CREATE_THREAD_LPCMESSAGE CreateThreadRequest; // 0x10001
CSRSS_GETTEMPFILENAME_LPCMESSAGE GetTempFileNameRequest; // 0x10002
CSRSS_EXIT_PROCESS_LPCMESSAGE ExitProcessRequest; // 0x10003

// Win2K only!
CSRSS_DEBUGPROCESS_LPCMESSAGE DebugActiveProcessRequest; // 0x10004

// For Win2K and XP, called as part of process creation
CSRSS_NLSGETUSERINFO_LPCMESSAGE NlsGetUserInfoRequest; // 0x1001A (Win2K)
// 0x1001E (XP)
};

} Data;

} CSR_API_MESSAGE, *PCSR_API_MESSAGE;



The Header:

Code:

typedef struct _LPC_MESSAGE_HEADER {
USHORT DataSize;
USHORT MessageSize;
USHORT MessageType;
USHORT VirtualRangesOffset;
CLIENT_ID ClientId;
ULONG MessageId;
ULONG SectionSize;
// UCHAR Data[1];
} LPC_MESSAGE_HEADER, *PLPC_MESSAGE_HEADER;



And a few of the more useful undocumented LPC_MESSAGE Data structures. These are my proposed working definitions that may be incomplete.

Code:

// Structure defining the LPC_MESSAGE Data used with
// CreateProcessW -> CsrClientCallServer -> NtRequestWaitReplyPort

typedef struct _CSRSS_CREATE_PROCESS_LPCMESSAGE {

ULONG ReturnStatus; // for Win2K ONLY this is lpStartAddress in the Request message
ULONG Unknown1;
PROCESS_INFORMATION lpProcessInformation;
CLIENT_ID DebuggerClientId; // valid if debugger attached to process
ULONG dwCreationFlags;
ULONG Unknown2;
ULONG Unknown3;
ULONG Unknown4;

} CSRSS_CREATE_PROCESS_LPCMESSAGE, *PCSRSS_CREATE_PROCESS_LPCMESSAGE;

typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
ULONG dwProcessId;
ULONG dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION;


Code:

// Structure defining the LPC_MESSAGE Data used with
// CreateThread -> CreateRemoteThread -> CsrClientCallServer -> NtRequestWaitReplyPort

typedef struct _CSRSS_CREATE_THREAD_LPCMESSAGE {

ULONG ReturnStatus;
ULONG Unknown1;
HANDLE hThread;
CLIENT_ID ClientId;

} CSRSS_CREATE_THREAD_LPCMESSAGE, *PCSRSS_CREATE_THREAD_LPCMESSAGE;


Code:

// Structure defining the LPC_MESSAGE Data used with
// ExitProcess -> CsrClientCallServer -> NtRequestWaitReplyPort

typedef struct _CSRSS_EXIT_PROCESS_LPCMESSAGE {

ULONG ReturnStatus; // uExitCode;
ULONG Unknown1;
ULONG ErrorStatus;

} CSRSS_EXIT_PROCESS_LPCMESSAGE, *PCSRSS_EXIT_PROCESS_LPCMESSAGE;


Code:

// Structure defining the LPC_MESSAGE Data used with
// DebugActiveProcess -> CsrClientCallServer -> NtRequestWaitReplyPort
// Win2K Only!
typedef struct _CSRSS_DEBUGPROCESS_LPCMESSAGE {

ULONG ReturnStatus;
ULONG Unknown1; // FOR OLLY: offset of abnormal_termination in User32 (stack unwind)
ULONG dwProcessId;
CLIENT_ID DebuggerClientId;
ULONG AttachCompleteRoutine; // offset of BaseAttachComplete

} CSRSS_DEBUGPROCESS_LPCMESSAGE, *PCSRSS_DEBUGPROCESS_LPCMESSAGE;



Code:

typedef NTSTATUS (*ZWREQUESTWAITREPLYPORT)(
HANDLE PortHandle,
PLPC_MESSAGE Request,
PLPC_MESSAGE Reply
);



So what does this all mean? It means you can hook ZwRequestWaitReplyPort and filter the LPC messages based on ApiNumber. Therefore you've got a single hook to intercept both process and thread creation (as well as any of the other funky API's you might want to trap).

I used it for a number of reasons. Firstly, I simply dumped the raw LPC message output for everything, just to see what information was available. I also used the filtered hook as a location for injecting a dll or shellcode or tracing TLS Callbacks, or for preventing a process or thread from running (return STATUS_LPC_REPLY_LOST).



Here is a sample DbgPrint output capturing a process (Test.exe) starting and exiting, as well as a secondary thread being created with CreateThread.

Code:

LPCHOOK: A Process is being started

LPCHOOK: LPC_MESSAGE Header:
DataSize:0xa8
MessageSize:0xc4
MessageType:2 (LPC_REPLY)
VirtualRangesOffset:0
PID:46C (explorer.exe)
TID:404 (Win32StartAddress 75FA533D)
MessageId:7226
SectionSize:0

LPCHOOK: LPC_MESSAGE Data: (42 dwords)
Reserved:0
ApiNumber:10000
ReturnStatus:0
Unknown1:36
hProcess:2c0
hThread:1a8
dwProcessId:378 (Test.exe)
dwThreadId:17C (Win32StartAddress 4019D0)
DebuggerPID:0 ((null))
DebuggerTID:0
dwCreationFlags:4000410
Unknown2:0
Unknown3:21
Unknown4:193d9a4


LPCHOOK: A Thread is being created

LPCHOOK: LPC_MESSAGE Header:
DataSize:0x1c
MessageSize:0x38
MessageType:2 (LPC_REPLY)
VirtualRangesOffset:0
PID:378 (Test.exe)
TID:17C (Win32StartAddress 4019D0)
MessageId:72be
SectionSize:0

LPCHOOK: LPC_MESSAGE Data: (7 dwords)
Reserved:0
ApiNumber:10001
ReturnStatus:0
Unknown1:0
hThread:30
ProcessId:378 (Test.exe)
ThreadId:178 (Win32StartAddress 401351)


LPCHOOK: A process is being exited

LPCHOOK: LPC_MESSAGE Header:
DataSize:0x14
MessageSize:0x30
MessageType:2 (LPC_REPLY)
VirtualRangesOffset:0
PID:378 (Test.exe)
TID:17C (Win32StartAddress 4019D0)
MessageId:72cc
SectionSize:0

LPCHOOK: LPC_MESSAGE Data: (5 dwords)
Reserved:0
ApiNumber:10003
uExitCode:0
Unknown1:82
ErrorStatus:0




Here is another thread for reference, be sure to make use of (but confirm on your Windows version) Alex Ionescu's definitions if you decide to play with this stuff.

http://www.woodmann.com/forum/showthread.php?t=11256


Cheers,
Kayaker

BanMe
May 19th, 2009, 13:21
This is a great preemptive detection method that could be used from kernel mode to initiate the user mode hooks onto a targeted process(es)...
I also noticed alex ionescue mentioned something about being able to make our own protocol on-top of LPC(RPC,SMSS,some others) LPC_MESSAGE indicates 64 DWORD's can be sent as "Data" and going over kayaker's CSR_API_MESSAGE none of the field exceed this mark.so I was wondering to what extent could this protocol be extended in terms of size?..

Thanks again Kayaker
regards BanMe

Kayaker
May 19th, 2009, 20:29
That's an interesting question BanMe (I don't think that will be necessary btw )

You mentioned something about already setting up a client/server LPC protocol for your app. That's an interesting approach. That's actually why I started looking into the LPC mechanism, as a possible means of semi-covert communication for a protection or otherwise. I never went anywhere with the idea, but it may have some potential and I've never really seen it used outside of regular Windows operation, though maybe some applications do use it for other purposes.

I notice in the following article that the "Short LPC message" has a maximum data chunk of 0x130 bytes, and if you want to transfer larger blocks you must use a mapped section, which I believe you already mentioned you were thinking of making use of.

http://www.zezula.net/en/prog/lpc.html

Regards,
Kayaker

BanMe
May 20th, 2009, 11:28
yes ive read that particular peice about a year or so ago

I used alot of the idea's presented there and in the article about WSLI located http://http://74.125.47.132/search?q=cache:NbNcIrkb2VUJ:www.blackhat.com/presentations/bh-europe-06/bh-eu-06-Cerrudo/bh-eu-06-Cerrudo-up.pdf+WLSI&cd=10&hl=en&ct=clnk&gl=us ("http://http://74.125.47.132/search?q=cache:NbNcIrkb2VUJ:www.blackhat.com/presentations/bh-europe-06/bh-eu-06-Cerrudo/bh-eu-06-Cerrudo-up.pdf+WLSI&cd=10&hl=en&ct=clnk&gl=us") what he presents as a vulnerability,I say can be refined and used as a strength if done in the correct way...

BanMe
July 12th, 2009, 21:28
wow its been that long o0
ok so I think I am at the juncture to where im at the ending of my last post..and Now Im going to Implement a Custom LPC Protocol for the RPC of my APP..just like the CSR_API_MESSAGE above all fields in the data union can be indexed with the ApiNumber or hopefully something like that..this functionality is the precursor and implementor of the plugin system so yea any and all help suggestions or criticisms are welcome, only thing left after the Custum RPC is to implement NativeIO based NativeBootIO In the Server...as to how im going to attain a window to write to..ive no clue..(10 miins later)
Absolutly beautiful..I nearly teared up when I saw AllocConsoleInternal and SetupHandlers, just need to emulate the functionality..which means more time till I get a feasible working environment for you to enjoy.. so I would like to formally request assistance..in the latter area of emulating the Console Windows functionality from kernel32..I'll be able to answer questions,and I could definitly go for some spare hands.if this works this will prolly be the only legitly coded native program with "system" account and a console window attached.. for (s)input through the keyboard the (s) is for short type command first letter (hit enter) it pops up command + space u type params or help and it goes accordingly) I want it to be smart and be able to teach the person using it about what it does...hopefully to in the end attain a more respondant user base this code is turning out to be a rapidly expanding POC..

Thanks will be given to any who thinks they can do this,
and the obvious Credits and references.. hopefully someone is up for some fun..

regards BanMe

Kayaker
July 12th, 2009, 23:39
Maybe you've seen this:

Windows Subsytem Csrss

http://www.ivanlef0u.tuxfamily.org/?p=188

http://ivanlef0u.free.fr/repo/MyGetConsoleTitle.rar


In the example he gets the title of the current console window by calling CsrClientCallServer with the internal API_NUMBER for kernel32!GetConsoleTitle (20226h). Yes, CSR_MAKE_API_NUMBER(CONSRV_SERVERDLL_INDEX, CONSRV_FIRST_API_NUMBER+38) equates to the required 20226h.

A handle to the console window is taken from _TEB->_PEB->_RTL_USER_PROCESS_PARAMETERS.ConsoleHandle with this snippet

Code:

HANDLE GetConsoleHandle(VOID)
{
__asm
{
mov eax, fs:[18h]
mov eax, [eax+30h]
mov eax, [eax+10h]
mov eax, [eax+10h]
}
}




The protocol (CsrAllocateCaptureBuffer / CsrCaptureMessageBuffer / CsrClientCallServer) seems to be similar to that of AllocConsoleInternal.

http://www.openrce.org/reference_library/win32_call_chains/2003SP1/KERNEL32/AllocConsoleInternal

Windows 2003 SE SP1 >> KERNEL32 >> AllocConsoleInternal
1. __SEH_prolog
2. CsrAllocateCaptureBuffer
3. SetLastError
4. __security_check_cookie
5. __SEH_epilog
6. CsrCaptureMessageBuffer
7. CsrClientCallServer
8. RtlNtStatusToDosError
9. NtWaitForMultipleObjects
10. NtClose


Something similar could probably be done for AllocConsoleInternal using the CsrClientCallServer API_NUMBER of 20224h.

I'm not sure why there are multiple calls to CsrCaptureMessageBuffer in AllocConsoleInternal though, necessitating the call to NtWaitForMultipleObjects. It might be because it's only normally called from AllocConsole. One would have to completely analyze the function to determine the reason.

Perhaps an emulation of AllocConsoleInternal with only a single call to CsrCaptureMessageBuffer might work for your purposes.


EDIT: I was looking at GetStdHandle, it seems to directly access STDOUT through _RTL_USER_PROCESS_PARAMETERS.StandardOutput. I was wondering if in your process, when you need the console window, is there any way you could simply access STDOUT and not have to generate a new console window?

Then I checked the 4 handles available from _RTL_USER_PROCESS_PARAMETERS
+0x010 ConsoleHandle
+0x018 StandardInput
+0x01c StandardOutput
+0x020 StandardError

For the ivanlef0u MyGetConsoleTitle code example, all 4 handles are valid at program start. However, for your Sin32 server, NONE of the handles are present in _RTL_USER_PROCESS_PARAMETERS, so maybe this last idea of nabbing STDOUT goes nowhere.

BanMe
July 13th, 2009, 02:02
yea Initialization of the stdhandles does come into play, ill just have to figure a way to rig them during initialization of the server and normalize the process parameters and what not..I plan on doing alot of stepping threw AllocConsole tommorow making sure there are no "hidden" calls to "user32" that could bite me..now as to setting up the handles the standard input will have to be the keyboard handle and the standard output will have to be the console buffer or something..but the error im not so sure of..

kayaker,thanks for always having a open mind and for maintaining the old ways for that I am grateful.

*update*
ahh this is fun stuff..
on my down into AllocConsole and I find tons of non effecient things for me to rethink and organize..there are other ways to do this then ripping out the code,just Map in the Kernel32, then using Virtual Memory to copy AllocConsole into and a smart code ripper capabale of following 'calls' around and back to and from rets and call chains., this way loses because we gain nothing, by doing it this way.we lose out on the expierence of doing something worth doing and the chance to hand code something in asm (again)excites me..lol.

If I encounter errors I will have to write it out anyways.. so that idea fails..and the idea of hand coding the whole thing..there are 5 calls to CsrCaptureBuffer: stepped over them for now..
Many Ineffectient internal functions that need to be optimized into a single blob.

*kayaker*
Console makes first Appearance on 20224h call..Great benchmark! ty



regards BanMe

BanMe
July 13th, 2009, 12:30
doing some cleanup of my blog..
sources will be up soon..

see my thread on "rekindled hope" for more info on the currently discussed topic...

also on Windows XP sp~sp3 can any verify the dlls loaded into csrss for me..

regards BanMe