首页
社区
课程
招聘
[原创]控制台监控
发表于: 2015-10-20 13:02 15200

[原创]控制台监控

2015-10-20 13:02
15200
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直播授课

收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 144
活跃值: (748)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
回复一下。这个是不错的思路。很多游戏都有这类输出。
2015-10-20 20:32
0
雪    币: 39
活跃值: (198)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
发现NtDeviceIoControlFile 这个函数功能强大啊
2015-10-20 23:42
0
雪    币: 284
活跃值: (3824)
能力值: ( LV5,RANK:75 )
在线值:
发帖
回帖
粉丝
4
+ win7 x64 控制台监控
2016-7-25 13:35
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
2016-7-25 15:42
0
游客
登录 | 注册 方可回帖
返回