xp控制台监控网上有开源代码sebek
win2008(vista)控制台监控
与XP的变化为:AllocConsole -> NtConnectPort -> L"XXXX\\Windows\\ApiPort" XXXX为任意,判断后面的字符匹配;
其他无变化
win7控制台监控
函数流程:
AllocConsole ->AllocConsoleInternal->CsrClientConnectToServer->CsrpConnectToServer->NtConnectPort->L"\\RPC Control\\ConsoleLPC"
WriteConsoleW->WriteConsoleInternal->ConsoleClientCallServer->NtRequestWaitReplyPort
ReadConsoleW ->ReadConsoleInternal ->ConsoleClientCallServer->NtRequestWaitReplyPort
->WriteConsoleW
->ConsoleClientCallServer(a1,...)
a1
+ 0 4B
+ 4 0 4B
+ 18 0 4B ((char*)pBuf + ConsolePortMemoryRemoteDelta), BufLen >= 0x50时
+ 1C 30-write 29-read 4B
+ 20 status 结果 4B NTSTATUS
+ 2C WCHAR buf[]
+ 80 BufLen 4B
+ 88 IsInBuf 1B char // 内容是否存在+2C处的buf中,BufLen < 0x50时为1,否则在+18处。
+ 89 IsWchar 1B char
注意!
上面的pBuf: pBuf+0x14 处才是字符串起址
ConsolePortMemoryRemoteDelta是一个偏移值,在sebek中有解
ReadConsoleW
+ 80 4B ((char*)pBuf + ConsolePortMemoryRemoteDelta)
+ 84 BufLen 4B
+ 98 IsWchar 1B char
win8控制台监控 - IDA(KernelBase.dll)
AllocConsole->ConsoleAllocate->ConsoleCreateHandle->NtCreateFile->L"\\Device\\ConDrv\\Server"
WriteConsoleW->ConsoleCallServerGeneric->NtDeviceIoControlFile
其实仅需:
NTSTATUS Hook_NtDeviceIoControlFile(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_ ULONG IoControlCode,
_In_opt_ PVOID InputBuffer,
_In_ ULONG InputBufferLength,
_Out_opt_ PVOID OutputBuffer,
_In_ ULONG OutputBufferLength
)
{
NTSTATUS status = Real_NtDeviceIoControlFile(FileHandle,
Event,
ApcRoutine,
ApcContext,
IoStatusBlock,
IoControlCode,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength
);
if ( NT_SUCCESS(status) )
{
if (IoControlCode == 0x500016)
{
ULONG code = *(PULONG)*(PULONG)((PCHAR)InputBuffer + 0x10);
if ( code == 0x1000006 )
{
KdPrint(( "WriteConsole : Len %d\n", *(PULONG)((PCHAR)InputBuffer + 0x14) ));
KdPrint(( "WriteConsole : %ws\n", (PWCHAR)*(PULONG)((PCHAR)InputBuffer + 0x18) ));
}
else if (code == 0x1000005)
{
KdPrint(( "ReadConsole : Len %d\n", *(PULONG)((char*)*(PULONG)((PCHAR)InputBuffer + 0x10) + 0x18) ));
KdPrint(( "ReadConsole : %ws\n", *(PWCHAR*)((char*)*(PULONG)((PCHAR)InputBuffer + 0x10) + 0x2C) ));
}
}
}
return status;
}
PS:关于控制台输出的重定位问题,sebek中有解:
Hook NtReadFile, NtWriteFile,
if( FileHandle == pTIB->pPEB->ProcessParameters->StandardOutput ||
FileHandle == pTIB->pPEB->ProcessParameters->StandardInput ||
FileHandle == pTIB->pPEB->ProcessParameters->StandardError )
取内容即可。
========= win7x64 (64位原生程序) =========
AllocConsole()->AllocConsoleInternal()->ConsoleConnect()->NtConnectPort()
int printf (const char *format, ...)
{
if (!format)
goto L_Error;
ftbuf()->flush()->write()->write_nolock()->_imp_WriteFile()->
Kernel32!WirteFileImplementation():
if (HFILE & 0x10000003 == 3)
{
WriteConsoleInternal()
}
L_Error:
// ...
return 0;
}
NTSTATUS __fastcall WriteConsoleInternal(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, char IsWchar)
{
__int64 p; // rax@14
LPDWORD pulBytesWritten; // rsi@1
LPCVOID lpBuffer1; // r12@1
__int64 p1; // rdi@5
NTSTATUS status; // eax@8
unsigned int StrLen; // ecx@10
char a1; // [sp+20h] [bp-E8h]@6
NTSTATUS status1; // [sp+54h] [bp-B4h]@8
HANDLE hFile1; // [sp+60h] [bp-A8h]@2
char InsideBuf; // [sp+68h] [bp-A0h]@5
char *pBuf; // [sp+B8h] [bp-50h]@5
unsigned int BufLen; // [sp+C0h] [bp-48h]@3
char IsInBuf; // [sp+D0h] [bp-38h]@5
char IsWchar1; // [sp+D1h] [bp-37h]@4
pulBytesWritten = lpNumberOfBytesWritten;
lpBuffer1 = lpBuffer;
if ( !*(_QWORD *)(*(_QWORD *)(*(_QWORD *)(*MK_FP(__GS__, 0x30i64) + 0x60i64) + 0x20i64) + 0x10i64) )
return 0xC0000008;
hFile1 = hFile;
if ( IsWchar )
{
nNumberOfBytesToWrite *= 2;
BufLen = nNumberOfBytesToWrite;
}
else
{
BufLen = nNumberOfBytesToWrite;
}
IsWchar1 = IsWchar;
if ( nNumberOfBytesToWrite > 0x50 )
{
p = ConsoleAllocateCaptureBuffer(1u, nNumberOfBytesToWrite);
p1 = p;
if ( !p )
return 0xC0000017;
ConsoleCaptureMessageBuffer(p, lpBuffer1, BufLen, (void **)&pBuf);
IsInBuf = 0;
}
else
{
pBuf = &InsideBuf;
memcpy_0(&InsideBuf, lpBuffer, nNumberOfBytesToWrite);
p1 = 0i64;
IsInBuf = 1;
}
ConsoleClientCallServer((__int64)&a1, p1, 30, 120);
if ( p1 )
RtlFreeHeap(ConsolePortHeap, 0i64, p1);
status = status1;
if ( status1 >= 0 && pulBytesWritten )
{
StrLen = BufLen;
*pulBytesWritten = BufLen;
if ( IsWchar )
*pulBytesWritten = StrLen >> 1;
}
return status;
}
NTSTATUS
NTAPI
Hook_NtRequestWaitReplyPort(
IN HANDLE PortHandle,
IN PPORT_MESSAGE RequestMessage,
OUT PPORT_MESSAGE ReplyMessage
)
typedef struct _PORT_MESSAGE {
char a1[0x30]; // [sp+20h] [bp-E8h]@6
ULONG ReadOrWrite;
NTSTATUS status; // [sp+54h] [bp-B4h]@8
ULONG64 dump1;
HANDLE hFile; // [sp+60h] [bp-A8h]@2
char InsideBuf[0x50];// [sp+68h] [bp-A0h]@5
char *pBuf; // [sp+B8h] [bp-50h]@5
unsigned int BufLen; // [sp+C0h] [bp-48h]@3
ULONG32 dump2[3];
char IsInBuf; // [sp+D0h] [bp-38h]@5
char IsWchar; // [sp+D1h] [bp-37h]@4
} PORT_MESSAGE, *PPORT_MESSAGE;
write 字节数小于 0x50时 IsInBuf 为 TRUE,内容存在 InsideBuf 里面;
否则内容在 pBuf - VirtualOffset 里;
两者都需要判断 IsWchar。
VirtualOffset 需要在 NtConnectPort 的时候获取;
NTSTATUS
Hook_NtConnectPort(
OUT PHANDLE PortHandle,
IN PUNICODE_STRING PortName,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
IN OUT PPORT_SECTION_WRITE WriteSection OPTIONAL,
OUT PVOID ServerSharedMemory OPTIONAL,
OUT PULONG MaximumMessageLength OPTIONAL,
IN PVOID ConnectionInfo OPTIONAL,
IN PULONG ConnectionInfoLength OPTIONAL
)
memcmp( (CHAR*)PortName->Buffer, // win7x64
L"\\RPC Control\\console",
sizeof(L"\\RPC Control\\console") - sizeof(UNICODE_NULL) ) == 0
typedef struct _PORT_SECTION_WRITE {
ULONG Length;
HANDLE hSection;
ULONG_PTR SectionOffset;
ULONG_PTR ViewSize;
PVOID ViewBase;
PVOID TargetViewBase;
} PORT_SECTION_WRITE, *PPORT_SECTION_WRITE;
VirtualOffset = (ULONG)WriteSection->TargetViewBase - (ULONG)WriteSection->ViewBase;
NTSTATUS __fastcall ReadConsoleInternal(HANDLE hConsoleInput, const LPVOID lpBuffer, DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, PCONSOLE_READCONSOLE_CONTROL pInputControl, char IsWchar, signed __int16 ExeNameLength, void *ExeNameBuffer)
{
LPDWORD pStrLen; // r14@1
ULONG WcsLen1; // er12@1
const void *lpBuffer1; // r15@1
signed __int16 ExeNameLength1; // ax@1
__int64 p; // rax@4
__int64 p1; // rdi@4
NTSTATUS status; // eax@5
NTSTATUS status1; // esi@8
PCONSOLE_READCONSOLE_CONTROL pInputControl1; // rbx@11
ULONG InitialCharBytes; // eax@14
NTSTATUS status2; // esi@24
unsigned int Size1; // edx@25
char a1_1; // [sp+50h] [bp-F8h]@24
NTSTATUS status3; // [sp+84h] [bp-C4h]@24
HANDLE hConsoleInput1; // [sp+90h] [bp-B8h]@1
__int16 ExeNameLength2; // [sp+98h] [bp-B0h]@3
char Dst; // [sp+9Ah] [bp-AEh]@3
void *pBuf; // [sp+F0h] [bp-58h]@6
size_t Size; // [sp+F8h] [bp-50h]@3
ULONG nInitialChars; // [sp+100h] [bp-48h]@8
ULONG dwCtrlWakeupMask; // [sp+104h] [bp-44h]@8
ULONG v29; // [sp+108h] [bp-40h]@8
char IsWchar1; // [sp+10Ch] [bp-3Ch]@1
pStrLen = lpNumberOfCharsRead;
WcsLen1 = nNumberOfCharsToRead;
lpBuffer1 = lpBuffer;
hConsoleInput1 = hConsoleInput;
IsWchar1 = IsWchar;
ExeNameLength1 = ExeNameLength;
if ( (unsigned __int16)ExeNameLength > 40u )
ExeNameLength1 = 40;
ExeNameLength2 = ExeNameLength1;
memcpy_0(&Dst, ExeNameBuffer, 2i64 * (unsigned __int16)ExeNameLength1);
LODWORD(Size) = 2 * WcsLen1;
HIDWORD(Size) = 2 * WcsLen1;
if ( 2 * WcsLen1 <= 0x50 )
{
pBuf = &Dst;
p1 = 0i64;
}
else
{
p = ConsoleAllocateCaptureBuffer(1u, 2 * WcsLen1);
p1 = p;
if ( !p )
return 0xC0000017;
ConsoleCaptureMessageBuffer(p, 0i64, HIDWORD(Size), &pBuf);
}
nInitialChars = 0;
dwCtrlWakeupMask = 0;
v29 = 0;
status1 = 0;
if ( IsWchar && pInputControl )
{
if ( *(_DWORD *)(*(_QWORD *)(*MK_FP(__GS__, 0x30i64) + 0x60i64) + 0x12Ci64) >= 4u )
{
pInputControl1 = pInputControl;
if ( pInputControl->nLength == 16 )
{
if ( pInputControl->nInitialChars <= WcsLen1 )
{
InitialCharBytes = 2 * pInputControl->nInitialChars;
nInitialChars = 2 * pInputControl->nInitialChars;
if ( pInputControl->nInitialChars )
memcpy_0(pBuf, lpBuffer1, InitialCharBytes);
dwCtrlWakeupMask = pInputControl->dwCtrlWakeupMask;
status1 = 0;
}
else
{
status1 = 0xC000000D;
}
goto L_Error;
}
}
status1 = 0;
}
pInputControl1 = 0i64;
L_Error:
if ( status1 < 0 && pInputControl1 )
{
if ( p1 )
ConsoleFreeCaptureBuffer(p1);
status = status1;
}
else
{
ConsoleClientCallServer((__int64)&a1_1, p1, 29, 128);
status2 = status3;
if ( status3 >= 0 )
{
Size1 = Size;
*pStrLen = Size;
if ( IsWchar )
{
*pStrLen = Size1 >> 1;
if ( pInputControl1 )
{
pInputControl1->dwControlKeyState = v29;
Size1 = Size;
status2 = status3;
}
}
memcpy_0((void *)lpBuffer1, pBuf, Size1);
}
if ( p1 )
{
ConsoleFreeCaptureBuffer(p1);
status2 = status3;
}
if ( status2 == 0x101 )
{
NtYieldExecution();
status2 = 0xC0000120;
}
status = status2;
}
return status;
}
NTSTATUS
NTAPI
Hook_NtRequestWaitReplyPort(
IN HANDLE PortHandle,
IN PPORT_MESSAGE RequestMessage,
OUT PPORT_MESSAGE ReplyMessage
)
typedef struct _PORT_MESSAGE_READ {
char a1[0x30]; // [sp+50h]
ULONG ReadOrWrite;
NTSTATUS status; // [sp+84h]
ULONG64 dump1;
HANDLE hFile; // [sp+90h]
USHORT ExeNameLength; // [sp+98h]
char InsideBuf[0x56];// [sp+9Ah]
char *pBuf; // [sp+F0h]
ULONG BufLen; // [sp+F8h]
ULONG32 dump2[4];
char IsWchar; // [sp+10Ch]
} PORT_MESSAGE_READ, *PPORT_MESSAGE_READ;
内容存在 pBuf - VirtualOffset, 需要判断 IsWchar。
关于重定向:
Hook_NtReadFile
Hook_NtWriteFile
_EPROCESS->_PEB->_RTL_USER_PROCESS_PARAMETERS
if( FileHandle == pPEB->ProcessParameters->StandardOutput ||
FileHandle == pPEB->ProcessParameters->StandardInput ||
FileHandle == pPEB->ProcessParameters->StandardError )
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课