|
-
Apr 19th, 2007, 08:28 PM
#1
Thread Starter
Lively Member
Subclassing SAS Window
Hi, I have recently been asked by a neighbor of mine if I could create a security application with methods to secure a windows desktop. Now I know there are a billion ways to do it in the registry but I figure it would be a great learning experience to see how well I can do this programmatically.
Now I have created LowLevelKey hooks to disable common keys like Alt+Tab and window key functions but the Ctrl Alt Del key combo had me confused at first. Well with research I have found that this Hotkey is monitored by Winlogon.exe and specifically its SAS Window.
So I spent a few days thinking out various methods to handle this. 1st I was thinking about looking around for a Keyfilter hook driver (but since I am not familiar with C++ that is kind of rulled out)
Next I looked in the MS Database and looked around on rebuilding the GINA. But this method is really too messy, too complex and I think would be a lot more work. (Not to mention dangerous)
So my final solution was the SAS Window Subclass. I found a good exmaple here: http://www.codeproject.com/win32/AntonioWinLock.asp yet since i dont know C++ it has been a difficult past weeks to try and convert into vb6. (These memory API functions kill me hah) anyways..
So I was wondering if anyone has done this in VB6 yet? If so do you care to share your module or function?
Most likely, I am thinking that a lot of people have probably not since the real internals of windows are coded mostly by C++ people.
So my other question is, does anyone know of a C++ or VC++ to VB6 to VB.net converter?
This would be the ultimate find if anyone knows of any, since this would greatly help me out in other project where I attempt to analyze C code and manually code and convert it line by line, which for myself seems to have a 90% fail rate. (They don't have to be free, I would probably pay for something that valuable)
Summary:
1. Has anyone ever Subclassed the Winlogon.exe SAS Window in VB?
2. If not would anyone be willing to give me a hand from AIM or e-mail or something in the process of converting this example to VB.
3. Does anyone know of a C to VB converter?
-
Apr 24th, 2007, 02:16 PM
#2
Frenzied Member
Re: Subclassing SAS Window
By the looks of it, you have no choice, but to use some c++ because it requires a win32 dll to subclass an external process. The author in that website you mentioned did mention using WriteProcessMemory, but like he said, its not very easy. I'd ususally use the SetWindowsHookEx method or the CreateRemoteThread when trying to inject code to external processes.
-
Apr 24th, 2007, 04:31 PM
#3
Thread Starter
Lively Member
Re: Subclassing SAS Window
Do you have any examples posted like at pscode or something where you demonstrate this remote code injection. Because once I get the code injected and create a remote thread, then its half the work I have to do.
I then have to figure out how C++ uses hooks by comparing it with C++ Keyhook examples to my VB Keyhook examples.
But yes, your code could help me a lot, because that C++ code posted uses the code injection method which I have yet to find an example of in VB. I mean I have seen many with the dll injection, but this is code injection. So I would love to take a look.
Thanks.
-
Apr 25th, 2007, 04:49 PM
#4
Frenzied Member
Re: Subclassing SAS Window
-
Apr 25th, 2007, 08:06 PM
#5
Thread Starter
Lively Member
Re: Subclassing SAS Window
Interesting code.
This does seem to help out with some of the coding. Yet, how can I create a remote thread through injection of CODE instead of a DLL.
Apparently that is what this guy does, but I dont quite understand how it is possible.
Any Ideas?
-
Apr 26th, 2007, 10:54 AM
#6
Frenzied Member
Re: Subclassing SAS Window
The example given uses a dll actually. Let me explain how all this works. Basically, for you to subclass the external application, you need to make it call SetWindowLong() with the GWL_WNDPROC (as one of its parameter) in the external application's process. I'm assuming you already know that to subclass your own program, your program would call SetWindowLong as well. So it pretty much work the same way. The question is, how do you make the external application call that function. This is where CreateRemoteThread and the DLL comes in.
CreateRemoteThread uses (as one of its parameter) a pointer to its callback function. This callback is called everytime CreateRemoteThread is called. In our case, we'll make it point to the LoadLibrary() instead. Another parameter of CreateRemoteThread is the parameter that will be used by the callback function (which is LoadLibrary in our case). That parameter will be the pointer to the path of the DLL (which will contain the code to be injected). The string value of this path must be in the process memory of the external application, and this is done by using WriteProcessMemory(). THen when you call CreateRemoteThread, it will call the callback function, which will be LoadLibrary() and the call to LoadLibrary will cause the DLL to be loaded in the external process. Notice that the dll has a Dllmain() procedure. Everytime a dll is loaded, the Dllmain() is called. And anything called inside Dllmain() is now being CALLED BY THE EXTERNAL PROCESS. And that's pretty much how it works. If you look at http://www.vbforums.com/showthread.p...teremotethread again, you should see that it does how I explained it. You just need to make changes to the dll so that it suites your need.
-
Apr 26th, 2007, 02:35 PM
#7
Thread Starter
Lively Member
Re: Subclassing SAS Window
 Originally Posted by benmartin101
The example given uses a dll actually. Let me explain how all this works. Basically, for you to subclass the external application, you need to make it call SetWindowLong() with the GWL_WNDPROC (as one of its parameter) in the external application's process. I'm assuming you already know that to subclass your own program, your program would call SetWindowLong as well. So it pretty much work the same way. The question is, how do you make the external application call that function. This is where CreateRemoteThread and the DLL comes in.
CreateRemoteThread uses (as one of its parameter) a pointer to its callback function. This callback is called everytime CreateRemoteThread is called. In our case, we'll make it point to the LoadLibrary() instead. Another parameter of CreateRemoteThread is the parameter that will be used by the callback function (which is LoadLibrary in our case). That parameter will be the pointer to the path of the DLL (which will contain the code to be injected). The string value of this path must be in the process memory of the external application, and this is done by using WriteProcessMemory(). THen when you call CreateRemoteThread, it will call the callback function, which will be LoadLibrary() and the call to LoadLibrary will cause the DLL to be loaded in the external process. Notice that the dll has a Dllmain() procedure. Everytime a dll is loaded, the Dllmain() is called. And anything called inside Dllmain() is now being CALLED BY THE EXTERNAL PROCESS. And that's pretty much how it works. If you look at http://www.vbforums.com/showthread.p...teremotethread again, you should see that it does how I explained it. You just need to make changes to the dll so that it suites your need.
Ok well that does help make some more sence of it, although I am really confused on how this guy does it with a specific peice of code instead of a dll.
It looks like he is injecting a data structure and calling that, but how is this possible?
I actually just checked to verify that this method does work by not injecting any dll into the process. I mointored winlogon.exe's open dlls and used the vb app that he created that imports the function from the dll. I initially was, for a minute, thinking this dll is what is injected. Although it is for sure not the case. He did this purely by code injection instead of dll injection. (Which is better in my opinion since it doesn't need to rely on a dll to function properly)
So I have been trying to analyze this code down here:
Look at the very first block of code:
Apparently DataLocal is the Structure INJDATA and this is what he is injecting as shown here:
Code:
// Initialize INJDATA for GetSASWnd() call
strcpy(DataLocal.szClassName, "SAS Window class");
strcpy(DataLocal.szWindowName, "SAS window");
DataLocal.fnFindWindow = (FINDWINDOW) GetProcAddress(hUser32, "FindWindowA");
if (DataLocal.fnFindWindow == NULL)
__leave;
// Allocate memory in the remote process and write a copy of initialized INJDATA into it
size = sizeof(INJDATA);
pDataRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pDataRemote)
__leave;
if (!WriteProcessMemory(hProcess, pDataRemote, &DataLocal, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
__leave;
// Allocate memory in remote process and write a copy of GetSASWnd() into it
size = (PBYTE)AfterGetSASWnd - (PBYTE)GetSASWnd;
pGetSASWndRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pGetSASWndRemote)
__leave;
if (!WriteProcessMemory(hProcess, pGetSASWndRemote, &GetSASWnd, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
__leave;
// Start execution of remote GetSASWnd()
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE) pGetSASWndRemote,
pDataRemote,
0 ,
&dwThreadId);
Here is the structure:
Code:
typedef struct {
SETWINDOWLONG fnSetWindowLong; // Addr. of SetWindowLong()
CALLWINDOWPROC fnCallWindowProc; // Addr. of CallWindowProc()
FINDWINDOW fnFindWindow; // Addr. of FindWindow()
char szClassName[50]; // Class name = "SAS Window class"
char szWindowName[50]; // Window name = "SAS window"
HWND hwnd; // Window handle of injected process
WNDPROC fnSASWndProc; // Addr. of remote SASWindowProc
WNDPROC fnOldSASWndProc; // Addr. of old SASWindowProc
} INJDATA, *PINJDATA;
This structure seems to be what he is injecting as the "code"
Although,
I really have no clue how to do this in VB6 or I would just do this same, but I cant because I am not sure of the:
1. Addr. of SetWindowLong
2. Addr. of CallWindowProc
3. Addr. of FindWindow
4. Addr. of remote SASWindowProc.
5. Addr. of old SASWindowProc
By best guess would be something like:
Code:
Private Type DataRemote
aCallWinProc as Long 'Address of CallWindowProc
aFindWindow as Long 'Address of FindWindow
sClassName as String 'SAS Window Class Name
sWindowName as String 'SAS Window Text Name
hWindow as Long 'winlogon.exe Window Handle
aSASWindowProc as Long 'Address of remote SASWindowProc
aSASOldWindowProc as Long 'Address of old SASWindowProc
End Type
----------------------------------------------------------
'(After the handle has been opned......)
'Initialize INJDATA for GetSASWnd() call
Dim tDataRemote as DataRemote
tDataRemote.sClassName = "SAS Window class"
tDataRemote.sWindowName = "SAS window"
tDataRemote.aFindWindow = GetAddressofFunction (AddressOf FindWindowA() )
'Allocate memory in the remote process and write a copy of initialized INJDATA into it
Dim lSize as Long
Dim pDataRemote as Long
Dim pGetSASWndRemote as Long
Dim lNumBytesCopied as Long
Dim hThread as Long
'Allocate memory in the remote process and write a copy of initialized INJDATA into it
lSize = Len(tDataRemote)
pDataRemote = VirtualAllocEx(hProcess, 0, lSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
Call WriteProcessMemory(hProcess, pDataRemote, VarPtr(DataLocal), lSize, VarPtr(lNumBytesCopied))
'Allocate memory in remote process and write a copy of GetSASWnd() into it
lSize = AfterGetSASWnd - GetSASWnd
pGetSASWndRemote = VirtualAllocEx(hProcess, 0, lSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
Call WriteProcessMemory(hProcess, pGetSASWndRemote, VarPtr(GetSASWnd), lSize, VarPtr(dwNumBytesCopied))
'Start execution of remote GetSASWnd()
hThread = CreateRemoteThread(hProcess, vbNull, 0, pGetSASWndRemote, pDataRemote, 0, VarPtr(dwThreadId)
----------------------------------------------------------
Private Function GetAddressofFunction(ByVal lAddress As Long) As Long
'This function allows you to assign a function pointer to a vaiable:
'A dummy procedure that receives and returns the value of the AddressOf operator.
'This workaround is needed as you can't assign AddressOf directly to a member of a user-defined type, but you can assign it to another long and use that instead!
GetAddressofFunction = lAddress
End Function
'**************************************************************
' * Return the window handle of the remote process (Winlogon). *
' **************************************************************
Private Function GetSASWnd
Dim tDataRemote as DataRemote
GetSASwnd = FindWindowA (tDataRemote.szClassName, tDataRemote.szWindowName
End Function
Private Function AfterGetSASWnd
AfterGetSASWnd = 4
End Function
Am I on the right track or way off???
Please Help...
Last edited by altf4; Apr 26th, 2007 at 02:39 PM.
-
Apr 26th, 2007, 02:45 PM
#8
Thread Starter
Lively Member
Re: Subclassing SAS Window
Opps sorrry I forgot to post the Inject Code:
PART 1:
Code:
////////////////////////////////////////////// Inject Code ////////////////////////////////////////
/**************************************************************************************************************
* Some tips when using CreateRemoteThread()/WriteProcessMemory(). *
* *
* 1. Analise generated code. *
* Check injected functions for absolute addressing (calls, jumps, data references, ...) *
* and other generated code that shouldn't be there. *
* Use: *
* A) Project\Settings\C/C++\Listing Files\Listing file type=Assembly, Machine Code, and Source. *
* B) A disassembler (wdasm32). *
* C) A debugger (softice). *
* *
* 2. Turn off stack probes. *
* Check for __chkstk() references in the listing files. *
* A) Use #pragma check_stack(off). [DOESN'T SEEMS TO WORK ?!?] *
* B) Use less than 4K of local variables. *
* C) Augment the stack size: /Gs size (Project\Settings\C/C++\ProjectOptions) *
* *
* 3. Remove the /GZ switch in the debug build. *
* Check for __chkesp() references in the listing files. *
* A) Project\Settings\C/C++\Project Options *
* *
* 4. Disable incremental compilation (/Gi). *
* A) Use #pragma comment(linker, "/INCREMENTAL:NO") *
* B) Remove the /Gi switch (Project\Settings\C/C++\Customize\Enable incremental compilation=Off *
* C) Declare the functions as static. *
* *
* 5. Don't let optimization screw your code. *
* A) Turn off optimization (Project\Settings\C/C++\General\Optimizations=Disable(Debug) *
* B) Use #pragma optimize("", off) *
* C) Don't write functions with the same prototype (e.g. AfterFuncX()). Let them return different values. *
* *
* 6. Split switch() statements in 3 cases maximum, or use if/then/else. *
* *
* 7. Don't call any functions besides those in KERNEL32.LL and USER32.DLL (USER32.DLL isn't garanted to be *
* mapped into every process). *
* Use LoadLibrary()/GetProcAddress if you need functions from other libraries. *
* *
* 8. Don't use any static strings. *
* Pass them in INJDATA. *
* *
* 9. Don't call any function directly. *
* Copy each routine to the remote process individually and supply their addresses in INJDATA. *
* *
* 10. Good luck. *
* If you analise the generated code (using a disassembler) you should catch any errors before executing *
* the code (and crashing the process !). *
**************************************************************************************************************/
#pragma comment(linker, "/INCREMENTAL:NO") // Turns off incremental linking
// Global variables
DWORD PID; // PID of injected process
BYTE *pDataRemote; // Address of INJDATA in the remote process
BYTE *pSASWinProcRemote; // The address of SASWindowProc() in the remote process
#define DUMMY_ADDR 0x12345678 // Dummy addr of INJDATA
// INJDATA: Memory block passed to each remote injected function.
// We pass every function address or string data in this block.
typedef LONG (WINAPI *SETWINDOWLONG) (HWND, int, LONG);
typedef LRESULT (WINAPI *CALLWINDOWPROC) (WNDPROC, HWND, UINT, WPARAM, LPARAM);
typedef HWND (WINAPI *FINDWINDOW) (LPCTSTR, LPCTSTR);
typedef struct {
SETWINDOWLONG fnSetWindowLong; // Addr. of SetWindowLong()
CALLWINDOWPROC fnCallWindowProc; // Addr. of CallWindowProc()
FINDWINDOW fnFindWindow; // Addr. of FindWindow()
char szClassName[50]; // Class name = "SAS Window class"
char szWindowName[50]; // Window name = "SAS window"
HWND hwnd; // Window handle of injected process
WNDPROC fnSASWndProc; // Addr. of remote SASWindowProc
WNDPROC fnOldSASWndProc; // Addr. of old SASWindowProc
} INJDATA, *PINJDATA;
/*****************************************************************
* Subclassed window procedure handler for the injected process. *
*****************************************************************/
#pragma optimize("", off)
#pragma check_stack(off)
static LRESULT CALLBACK SASWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// INJDATA pointer.
// Must be patched at runtime !
INJDATA* pData = (INJDATA *)DUMMY_ADDR;
if (uMsg == WM_HOTKEY)
{
// Ctrl+Alt+Del
if (lParam == MAKELONG(MOD_CONTROL | MOD_ALT, VK_DELETE))
return 1;
// Ctrl+Shift+Esc
if (lParam == MAKELONG(MOD_CONTROL | MOD_SHIFT, VK_ESCAPE))
return 1;
}
// Call the original window procedure
return pData->fnCallWindowProc(pData->fnOldSASWndProc, hwnd, uMsg, wParam, lParam);
}
static int AfterSASWindowProc(void) {return 1;}
/*************************************************
* Subclass the remote process window procedure. *
* Return: 0=failure, 1=success *
*************************************************/
#pragma optimize("", off)
#pragma check_stack(off)
static DWORD WINAPI InjectFunc (INJDATA *pData)
{
// Subclass window procedure
pData->fnOldSASWndProc = (WNDPROC) pData->fnSetWindowLong (pData->hwnd, GWL_WNDPROC, (long)pData->fnSASWndProc);
return (pData->fnOldSASWndProc != NULL);
}
static int AfterInjectFunc(void) {return 2;}
/***********************************************************
* Restore the subclassed remote process window procedure. *
* Return: 0=failure, 1=success *
***********************************************************/
#pragma optimize("", off)
#pragma check_stack(off)
static DWORD WINAPI EjectFunc (INJDATA *pData)
{
return (pData->fnSetWindowLong(pData->hwnd, GWL_WNDPROC, (long)pData->fnOldSASWndProc) != 0);
}
static int AfterEjectFunc(void) {return 3;}
/**************************************************************
* Return the window handle of the remote process (Winlogon). *
**************************************************************/
#pragma optimize("", off)
#pragma check_stack(off)
static HWND WINAPI GetSASWnd (INJDATA *pData)
{
return (pData->fnFindWindow(pData->szClassName, pData->szWindowName));
}
static int AfterGetSASWnd(void) {return 4;}
Last edited by altf4; Apr 26th, 2007 at 02:48 PM.
-
Apr 26th, 2007, 02:46 PM
#9
Thread Starter
Lively Member
Re: Subclassing SAS Window
PART 2:
Code:
***************************************************************************
* Copies InjectFunc(), GetSASWnd() , SASWindowProc() and INJDATA to the *
* remote process. *
* Starts the execution of the remote InjectFunc(), which subclasses the *
* remote process default window procedure handler. *
* *
* Return value: 0=failure, 1=success *
***************************************************************************/
int InjectCode ()
{
HANDLE hProcess = 0; // Process handle
HMODULE hUser32 = 0; // Handle of user32.dll
BYTE *pCodeRemote; // Address of InjectFunc() in the remote process.
BYTE *pGetSASWndRemote; // Address of GetSASWnd() in the remote process.
HANDLE hThread = 0; // The handle and ID of the thread executing
DWORD dwThreadId = 0; // the remote InjectFunc().
INJDATA DataLocal; // INJDATA structure
BOOL fUnicode; // TRUE if remote process is Unicode
int nSuccess = 0; // Subclassing succeded?
DWORD dwNumBytesCopied = 0; // Number of bytes written to the remote process.
DWORD size; // Calculated function size (= AfterFunc() - Func())
int SearchSize; // SASWindowProc() dummy addr. search size
int nDummyOffset; // Offset in SASWindowProc() of dummy addr.
BOOL FoundDummyAddr; // Dummy INJDATA reference found in SASWindowProc() ?
HWND hSASWnd; // Window handle of Winlogon process
BYTE *p;
// Enable Debug privilege (needed for some processes)
if (!EnablePrivilege(SE_DEBUG_NAME, TRUE))
return 0;
// Get handle of "USER32.DLL"
hUser32 = GetModuleHandle("user32");
if (!hUser32)
return 0;
// Get remote process ID
PID = GetPIDFromName(szProcessName);
if (PID == -1)
return 0;
// Open remote process
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
if (!hProcess)
return 0;
__try
{
// Initialize INJDATA for GetSASWnd() call
strcpy(DataLocal.szClassName, "SAS Window class");
strcpy(DataLocal.szWindowName, "SAS window");
DataLocal.fnFindWindow = (FINDWINDOW) GetProcAddress(hUser32, "FindWindowA");
if (DataLocal.fnFindWindow == NULL)
__leave;
// Allocate memory in the remote process and write a copy of initialized INJDATA into it
size = sizeof(INJDATA);
pDataRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pDataRemote)
__leave;
if (!WriteProcessMemory(hProcess, pDataRemote, &DataLocal, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
__leave;
// Allocate memory in remote process and write a copy of GetSASWnd() into it
size = (PBYTE)AfterGetSASWnd - (PBYTE)GetSASWnd;
pGetSASWndRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pGetSASWndRemote)
__leave;
if (!WriteProcessMemory(hProcess, pGetSASWndRemote, &GetSASWnd, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
__leave;
// Start execution of remote GetSASWnd()
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE) pGetSASWndRemote,
pDataRemote,
0 ,
&dwThreadId);
// Failed
if (!hThread)
__leave;
// Wait for GetSASWnd() to terminate and get return code (SAS Wnd handle)
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, (PDWORD) &hSASWnd);
// Didn't found "SAS window"
if (!hSASWnd)
__leave;
// Cleanup
VirtualFreeEx(hProcess, pGetSASWndRemote, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, pDataRemote, 0, MEM_RELEASE);
pGetSASWndRemote = NULL;
pDataRemote = NULL;
// Allocate memory in remote process and write a copy of SASWindowProc() into it
size = (PBYTE)AfterSASWindowProc - (PBYTE)SASWindowProc;
pSASWinProcRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pSASWinProcRemote)
__leave;
if (!WriteProcessMemory(hProcess, pSASWinProcRemote, &SASWindowProc, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
__leave;
// Is remote process unicode ?
fUnicode = IsWindowUnicode(hSASWnd);
// Initialize the INJDATA structure
DataLocal.fnSetWindowLong = (SETWINDOWLONG) GetProcAddress(hUser32, fUnicode ? "SetWindowLongW" : "SetWindowLongA");
DataLocal.fnCallWindowProc = (CALLWINDOWPROC) GetProcAddress(hUser32, fUnicode ? "CallWindowProcW": "CallWindowProcA");
DataLocal.fnSASWndProc = (WNDPROC) pSASWinProcRemote;
DataLocal.hwnd = hSASWnd;
if (DataLocal.fnSetWindowLong == NULL ||
DataLocal.fnCallWindowProc == NULL)
{
__leave;
}
// Allocate memory in the remote process and write a copy of initialized INJDATA into it
size = sizeof(INJDATA);
pDataRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pDataRemote)
__leave;
if (!WriteProcessMemory(hProcess, pDataRemote, &DataLocal, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
__leave;
// Change dummy INJDATA address in SASWindowProc() by the real INJDATA pointer
p = (PBYTE)&SASWindowProc;
size = (PBYTE)AfterSASWindowProc - (PBYTE)SASWindowProc;
SearchSize = size - sizeof(DWORD) + 1;
FoundDummyAddr = FALSE;
for (; SearchSize > 0; p++, SearchSize--)
{
if (*(DWORD *)p == DUMMY_ADDR) // Found
{
nDummyOffset = p - (PBYTE)&SASWindowProc;
if (!WriteProcessMemory(hProcess, pSASWinProcRemote + nDummyOffset, &pDataRemote, sizeof(pDataRemote), &dwNumBytesCopied) ||
dwNumBytesCopied != sizeof(pDataRemote))
{
__leave;
}
FoundDummyAddr = TRUE;
break;
}
}
// Couldn't change the dummy INJDATA addr. by the real addr. in SASWindowProc() !?!
// Don't execute the remote copy of SASWindowProc() because the pData pointer is invalid !
if (!FoundDummyAddr)
{
__leave;
}
// Allocate memory in the remote process and write a copy of InjectFunc() to the allocated memory
size = (PBYTE)AfterInjectFunc - (PBYTE)InjectFunc;
pCodeRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pCodeRemote)
__leave;
if (!WriteProcessMemory(hProcess, pCodeRemote, &InjectFunc, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
__leave;
// Start execution of remote InjectFunc()
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE) pCodeRemote,
pDataRemote,
0 ,
&dwThreadId);
if (!hThread)
__leave;
// Wait for InjectFunc() to terminate and get return code
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, (PDWORD) &nSuccess);
// InjectFunc() successfull
// if (nSuccess)
// MessageBeep(0);
}
__finally
{
// Failed ?
if (!nSuccess)
{
// Release memory for INJDATA and SASWindowProc()
if (pDataRemote)
VirtualFreeEx(hProcess, pDataRemote, 0, MEM_RELEASE);
if (pSASWinProcRemote)
VirtualFreeEx(hProcess, pSASWinProcRemote, 0, MEM_RELEASE);
pDataRemote = NULL;
pSASWinProcRemote = NULL;
}
// Release remote GetSASWnd()
if (pGetSASWndRemote)
VirtualFreeEx(hProcess, pGetSASWndRemote, 0, MEM_RELEASE);
// Release remote InjectFunc() (no longer needed)
if (pCodeRemote)
VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
if (hThread)
CloseHandle(hThread);
}
CloseHandle(hProcess);
// Disable the DEBUG privilege
EnablePrivilege(SE_DEBUG_NAME, FALSE);
return nSuccess; // 0=failure; 1=success
}
-
Apr 26th, 2007, 02:47 PM
#10
Thread Starter
Lively Member
Re: Subclassing SAS Window
PART 3:
Code:
/**********************************************************************
* Copies EjectFunc() to the remote process and starts its execution. *
* The remote EjectFunc() restores the old window procedure. *
* *
* Return value: 0=failure, 1=success *
**********************************************************************/
int EjectCode ()
{
HANDLE hProcess; // Remote process handle
DWORD *pCodeRemote; // Address of EjectFunc() in the remote process
HANDLE hThread = NULL; // The handle and ID of the thread executing
DWORD dwThreadId = 0; // the remote EjectFunc().
int nSuccess = 0; // EjectFunc() success ?
DWORD dwNumBytesCopied = 0; // Number of bytes written to the remote process.
DWORD size; // Calculated function size (= AfterFunc() - Func())
// Enable Debug privilege (needed for some processes)
EnablePrivilege(SE_DEBUG_NAME, TRUE);
// Remote INDATA and SASWindowProc() must exist
if (!pDataRemote || !pSASWinProcRemote)
return 0;
// Open the process
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
if (hProcess == NULL)
return 0;
// Allocate memory in the remote process and write a copy of EjectFunc() to the allocated memory
size = (PBYTE)AfterEjectFunc - (PBYTE)EjectFunc;
pCodeRemote = (PDWORD) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pCodeRemote)
{
CloseHandle(hProcess);
return 0;
}
if (!WriteProcessMemory(hProcess, pCodeRemote, &EjectFunc, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
{
VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 0;
}
// Start execution of the remote EjectFunc()
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE) pCodeRemote,
pDataRemote,
0 ,
&dwThreadId);
// Failed
if (!hThread)
{
goto END;
}
// Wait for EjectFunc() to terminate and get return code
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, (PDWORD) &nSuccess);
// Failed to restore old window procedure ?
// Then leave INJDATA and the SASWindowProc()
if (nSuccess == 0)
goto END;
// Release memory for remote INJDATA and SASWindowProc()
if (pDataRemote)
VirtualFreeEx(hProcess, pDataRemote, 0, MEM_RELEASE);
if (pSASWinProcRemote)
VirtualFreeEx(hProcess, pSASWinProcRemote, 0, MEM_RELEASE);
pDataRemote = NULL;
pSASWinProcRemote = NULL;
// MessageBeep(0); // success
END:
if (hThread)
CloseHandle(hThread);
// Release EjectFunc() memory
if (pCodeRemote)
VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
CloseHandle(hProcess);
// Disable the DEBUG privilege
EnablePrivilege(SE_DEBUG_NAME, FALSE);
return nSuccess; // 0=failure; 1=success
}
-
Apr 26th, 2007, 04:23 PM
#11
Frenzied Member
Re: Subclassing SAS Window
To be honest, it appears complex me. Like he said, it takes very careful coding meaning its harder. I think the method with the dll is easier, and is moe common. I think his method may require knowledge in assembly.
Last edited by benmartin101; Apr 26th, 2007 at 04:29 PM.
-
Apr 26th, 2007, 04:34 PM
#12
Frenzied Member
Re: Subclassing SAS Window
If the CreateRemoteThread() is not for you, then you may want to look into SetWindowsHookEx(). There are threads here regarding this topic. It works somewhat similar to the first, in that you replace a callback function with you're own, and when this "custom" callback function is called by the external process, it will call whatever code you have placed in it. This, too, requires the use of a DLL.
-
Apr 26th, 2007, 05:12 PM
#13
Thread Starter
Lively Member
Re: Subclassing SAS Window
Hmm, well I want to try to achive this code method of doing it, because I can do it with a dll, or can at least inject it into a process.
But what I am trying to learn is how to inject this code structure in. If you have any ideas let me know.
I just need to figure out the right conversion for it. I am not a C++ coder, so hopfully someone can help me convert some of these lines into vb. I mean I have the concept and I can convert all the API and many functions used. But stuff dealing with the callback values in the structure or pointers and stuff are what really confuse me.
-
Apr 26th, 2007, 05:38 PM
#14
Frenzied Member
Re: Subclassing SAS Window
I think this is VB6 equivalent of INJDATA structure
vb Code:
public type
fnSetWindowLong as long
fnCllWindowProc as long
fnFindWindow as long
szClassName as string
szWindowName as string
hwnd as long
fnSasWndProc as long
fnOldSASWndProc as long
end type
-
Apr 26th, 2007, 06:06 PM
#15
Thread Starter
Lively Member
Re: Subclassing SAS Window
 Originally Posted by benmartin101
I think this is VB6 equivalent of INJDATA structure
vb Code:
public type
fnSetWindowLong as long
fnCllWindowProc as long
fnFindWindow as long
szClassName as string
szWindowName as string
hwnd as long
fnSasWndProc as long
fnOldSASWndProc as long
end type
Well yes I already had that (Shown in my above test example code) But I am trying to figure out how to set the values with the address of a function.
Also, are those VarPtr() functions in the correct locations? I am assuming the &Variable means pass the value's pointer right?
Do you see and flaws in the code I wrote just as a test?
-
Apr 26th, 2007, 06:21 PM
#16
Frenzied Member
Re: Subclassing SAS Window
this line:
vb Code:
tDataRemote.aFindWindow = GetAddressofFunction (AddressOf FindWindowA() )
I don't think using AddressOf will work. I think AddressOf only works if the function is from your own program; FindWindowA is from a dll, user32.dll i think. You would have to use GetProcAddress() like:
GetProcAddress("user32", "FindWindowA") would return the address of FindWindowA.
-
Apr 26th, 2007, 06:49 PM
#17
Thread Starter
Lively Member
Re: Subclassing SAS Window
 Originally Posted by benmartin101
this line:
vb Code:
tDataRemote.aFindWindow = GetAddressofFunction (AddressOf FindWindowA() )
I don't think using AddressOf will work. I think AddressOf only works if the function is from your own program; FindWindowA is from a dll, user32.dll i think. You would have to use GetProcAddress() like:
GetProcAddress("user32", "FindWindowA") would return the address of FindWindowA.
Ok thanks. Umm, do you know if my VarPtr() functions are in the correct locations?
-
Apr 27th, 2007, 10:28 AM
#18
Frenzied Member
Re: Subclassing SAS Window
They seem to be in correct locations. But the only way to really find out is by running it.
-
Apr 27th, 2007, 03:12 PM
#19
Thread Starter
Lively Member
Re: Subclassing SAS Window
Hey well Iv been trying to work with this code, but I have run into a problem
Do you know how to covert this code to vb? :
Code:
/**************************************************************
* Return the window handle of the remote process (Winlogon). *
**************************************************************/
static HWND WINAPI GetSASWnd (INJDATA *pData)
{
return (pData->fnFindWindow(pData->szClassName, pData->szWindowName));
}
static int AfterGetSASWnd(void) {return 4;}
Here was my attempt, but it did not work properly:
Code:
'**************************************************************
' * Return the window handle of the remote process (Winlogon). *
' **************************************************************
'Probelm:
Private Function GetSASWnd() As Long
Dim tDataLocal As InjectData
'1. Attempt 1
'GetSASWnd = FindWindow(tDataLocal.sClassName, tDataLocal.sWindowName)
'2. Attempt 2
'Dim pClassName As Long: pClassName = VarPtr(tDataLocal.sClassName)
'Dim pWindowName As Long: pClassName = VarPtr(tDataLocal.sClassName)
'Dim pFindWindow As Long: pFindWindow = VarPtr(tDataLocal.pFindWindow(pClassName, pWindowName))
'GetSASWnd = pFindWindow
'3. Attempt 3
'tDataLocal.sClassName =
'C++: GetSASWnd = (pData->fnFindWindow(pData->szClassName, pData->szWindowName))
End Function
Private Function AfterGetSASWnd() As Long
AfterGetSASWnd = 4
End Function
-
Apr 27th, 2007, 06:29 PM
#20
Frenzied Member
Re: Subclassing SAS Window
The c++ code shows tha its using a function pointer to call the function. The question is, which function is it pointing to? If its pointing to the FindWindow() function, then your first attempt is correct.
-
Apr 28th, 2007, 01:22 PM
#21
Thread Starter
Lively Member
Re: Subclassing SAS Window
 Originally Posted by benmartin101
The c++ code shows tha its using a function pointer to call the function. The question is, which function is it pointing to? If its pointing to the FindWindow() function, then your first attempt is correct.
Well something cant be right because take a look at this:
Code:
Public Sub InjectCode()
Dim lPID As Long
Dim hProcess As Long
Dim hUser32 As Long
Dim lSize As Long
Dim pDataRemote As Long
Dim pGetSASWndRemote As Long
Dim tDataLocal As InjectData
Dim lNumBytesCopied As Long
Dim sLibPath As String * 260
Dim lLinkToLibrary As Long
Dim NewModule As Long
'--------------
'Enable Debug privilege
Call EnableProcessPrivileges(GetCurrentProcessId, SE_Debug)
'Get handle of "USER32.DLL"
hUser32 = GetModuleHandle("user32.dll")
'Open Process:
lPID = GetPID("winlogon.exe", PD_ProcessName)
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, lPID)
'Initialize INJDATA for GetSASWnd() call
tDataLocal.sClassName = "SAS Window class"
tDataLocal.sWindowName = "SAS window"
tDataLocal.pFindWindow = GetProcAddress(hUser32, "FindWindowA")
'Allocate memory in the remote process and write a copy of initialized INJDATA into it
lSize = Len(tDataLocal) 'Should = 28, and lNumBytesCopied should = 28 after WriteProcessMemory
pDataRemote = VirtualAllocEx(hProcess, 0, lSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
Call WriteProcessMemory(hProcess, ByVal pDataRemote, ByVal VarPtr(tDataLocal), lSize, lNumBytesCopied)
MsgBox lNumBytesCopied
lNumBytesCopied = 0
'Allocate memory in remote process and write a copy of GetSASWnd() into it
lSize = AfterGetSASWnd - GetSASWnd
MsgBox lSize
MsgBox GetSASWnd
pGetSASWndRemote = VirtualAllocEx(hProcess, 0, lSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)
MsgBox pGetSASWndRemote
Call WriteProcessMemory(hProcess, ByVal pGetSASWndRemote, ByVal VarPtr(GetSASWnd), lSize, lNumBytesCopied)
MsgBox lNumBytesCopied
End Sub
'***************************************************************
' * Return the window handle of the remote process (Winlogon).
' **************************************************************
'Problem:
Private Function GetSASWnd() As Long
Dim tDataLocal As InjectData
'1. Attempt 1
GetSASWnd = FindWindow(tDataLocal.sClassName, tDataLocal.sWindowName)
'2. Attempt 2
'Dim pClassName As Long: pClassName = VarPtr(tDataLocal.sClassName)
'Dim pWindowName As Long: pClassName = VarPtr(tDataLocal.sClassName)
'Dim pFindWindow As Long: pFindWindow = VarPtr(tDataLocal.pFindWindow(pClassName, pWindowName))
'GetSASWnd = pFindWindow
'3. Attempt 3
'tDataLocal.sClassName =
'C++: GetSASWnd = (pData->fnFindWindow(pData->szClassName, pData->szWindowName))
End Function
Private Function AfterGetSASWnd() As Long
AfterGetSASWnd = 4
End Function
Here is why something is wrong:
lNumBytesCopied retruns 0
The reason why is because pGetSASWndRemote returns 0.....
meaning the size allocation is not correct.
lSize depends on those 2 functions where I am unsure about, so it obviously has seomthing to do this that. Then reason why I dont think method 1 is correct because it is like saying:
MemoryAllocationSize = 4 - WindowHandle
Which doesn't make sence.
So in conclusion, everthing works fine until I get up to the:
lSize = AfterGetSASWnd - GetSASWnd
So.... please help.
NOTE: it might be easier to help if you just slap in the above code into vb since I have many comments to help me along the way.
Last edited by altf4; Apr 28th, 2007 at 02:06 PM.
-
May 1st, 2007, 06:43 PM
#22
Thread Starter
Lively Member
Re: Subclassing SAS Window
Any ideas anyone?
I am kind of dead in the water here.
-
Jun 14th, 2007, 10:08 AM
#23
Thread Starter
Lively Member
Re: Subclassing SAS Window
-
Dec 7th, 2008, 07:18 PM
#24
Thread Starter
Lively Member
Re: Subclassing SAS Window
Well after a year and a half of work in VB since this post asking for help, I finally figured it out!
Its funny, I don't really have a purpose for doing it anymore since I have found many better ways to protect a process (Such as removing the process from the list in the Kernel) but it was an interesting journey.
I was way over my head before, and not understanding about memory management and threads was a big mistake before trying to tackle this problem.
Anyway, just thought I would let everyone know that it is possible in VB6 without needing a C DLL. The trick is: making it with a VB active-x Dll with some mods (Thanks to Jim White for all his research and help how to successfully compile a win32 dll and call APIs using a TypeLibrary (generated from a .old)
Here is the thread for which helped out a lot with the DLL trouble shooting:
http://www.xtremevbtalk.com/showthread.php?p=1312981
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|