cmd_logger.zip/src/main.cpp
#include <string.h>
#include <string>
#include <vector>
#include <windows.h>
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/format.hpp>
boost::filesystem::path GetDllDir() {
wchar_t buffer[MAX_PATH];
if (0 == ::GetModuleFileNameW(::GetModuleHandleW(L"cmd_logger.dll"), buffer, _countof(buffer))) {
return boost::filesystem::path();
}
return boost::filesystem::path(buffer).remove_filename();
}
BOOL WINAPI d_ReadConsoleW(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, PCONSOLE_READCONSOLE_CONTROL lpReserved) {
const BOOL result = ::ReadConsoleW(hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, lpReserved);
if (result == FALSE || *lpNumberOfCharsRead == 0 ||
reinterpret_cast<const wchar_t*>(lpBuffer)[*lpNumberOfCharsRead-1] == L'\t')
{
return result;
}
const boost::filesystem::path path = GetDllDir() / L"command_history.txt";
boost::filesystem::wofstream ofs(path, std::ios::app | std::ios::binary);
ofs << std::wstring(reinterpret_cast<const wchar_t*>(lpBuffer), &reinterpret_cast<const wchar_t*>(lpBuffer)[*lpNumberOfCharsRead]);
return result;
}
bool ChangeIAT(HMODULE module) {
struct TargetProcInfo {
std::string dllName;
std::string procName;
unsigned int procAddress;
};
const TargetProcInfo targetList[] ={
{"kernel32.dll", "ReadConsoleW", reinterpret_cast<unsigned int>(d_ReadConsoleW)}, // WindowsXP vista 7
{"api-ms-win-core-console-l1-1-0.dll", "ReadConsoleW", reinterpret_cast<unsigned int>(d_ReadConsoleW)}, // Windows8
};
unsigned char * const baseAddr = reinterpret_cast<unsigned char *>(module == NULL ? ::GetModuleHandleA(NULL) : module);
const IMAGE_DOS_HEADER &mz = *reinterpret_cast<const IMAGE_DOS_HEADER *>(baseAddr);
const IMAGE_NT_HEADERS32 &pe = *reinterpret_cast<const IMAGE_NT_HEADERS32 *>(baseAddr + mz.e_lfanew);
const IMAGE_IMPORT_DESCRIPTOR *desc = reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR *>(baseAddr + pe.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
for (; desc->OriginalFirstThunk != 0; desc = ++desc) {
const char * const dllName = reinterpret_cast<const char *>(baseAddr + desc->Name);
const unsigned int *in = reinterpret_cast<unsigned int *>(baseAddr + desc->OriginalFirstThunk);
unsigned int *out = reinterpret_cast<unsigned int *>(baseAddr + desc->FirstThunk);
for (; *in != 0; ++in, ++out) {
if ((*in & 0x80000000) != 0) {
continue;
}
const char * const procName = reinterpret_cast<const char *>(baseAddr + *in + 2);
BOOST_FOREACH(const TargetProcInfo &target, targetList) {
if (::_stricmp(target.dllName.c_str(), dllName) != 0 || target.procName != procName) {
continue;
}
DWORD oldProtect;
::VirtualProtect(out, 4, PAGE_READWRITE, &oldProtect);
*out = target.procAddress;
::VirtualProtect(out, 4, oldProtect, &oldProtect);
}
}
}
return true;
}
BOOL APIENTRY DllMain(HANDLE , DWORD ul_reason_for_call, LPVOID) {
static HMODULE h_original = NULL;
switch(ul_reason_for_call) {
case DLL_PROCESS_ATTACH: {
if (!ChangeIAT(NULL)) {
return FALSE;
}
break;
}
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}