zoukankan      html  css  js  c++  java
  • Fport逆向分析以及C++实现

    Fport是一个可以在winXP上实现查询端口信息功能的软件。

    首先将文件拖入IDA分析

      找到main函数,通过与OD动态分析结合,发现输出信息都在一个keyFunction里完成。

      通过OD发现程序的主体逻辑大概是:Tcp和Udp操作类似,首先GetProcessHeap()获取当前堆,然后调用AllocateAndGetTcpExTableFromStack(),再将其返回信息送入workFunc()加工,最后由msgShow()输出到屏幕上。通过MSDN上查询可以知道:

      

      GetProcessHeap 返回当前进程堆句柄。

      

      【垃圾博客园写了一大堆没有保存按到鼠标全部没有了!!!!心态爆炸】

      API的功能是获取Tcp信息,第一个参数是一个指针,存放指向返回的tcpTable的指针,第三个参数是getProcessHeap返回的handle,其他都是立即数。经过调试发现,输出的pid和port信息全在tcpTable里面,通过输出和对workFunc的传参发现该表中结构体占4X6个字节,最后4个字节存放pid,9、10字节存放大端方式的port值。所以大胆推测workFunc只是对信息作一定的处理,最后方便msgShow统一地进行输出。进入workFunc验证

      

      看到根据pid获取程序名称,地址(zaigetFileAddress中)的功能也在此实现,stringFunc1应该就是对输出信息的处理。至此想要写出同样功能的程序我们只需要调用一次AllocateAndGetTcpExTableFromStack()即可,但是老师的意思似乎是要让我们分析这个API,于是要进到函数中去。(AllocateAndGetTcpExTableFromStack()是iphlpdll.dll里的)

    进入AllocateAndGetTcpExTableFromStack()

      ps:最开始的时候不知道IDA静态分析dll,用OD动态分析吃了不少苦头不过也增强了看汇编代码的能力。附上几张草稿纸

      

      由于最终目的是要写出同样功能的程序,所以只需要获得所有API的调用情况以及具体参数就可以了。

      

      函数的关系情况,initUnicodeString为createFile提供文件名,createEvent()为zwDeviceIoControlFile()提供handle,第一次调用的返回值为allocateHeap提供大小,第二次调用zwDeviceIoControlFile()返回了tcpTable于是zwDeviceIoControlFile()就是关键API,搞定了它的参数就可以获得pid和port。

       

      看上去这是一个和硬件打交道的API,从第二个参数开始讲起,Event就是CreateEvent返回的handle,第三四个是立即数0,第五个是指向PIO_STATUS_BLOCK的指针,这儿没有用,第六个看名字就知道比较关键在此是0x120003,后两个也比较关键Inputbuffer,告诉Api你想要做什么,都是立即数轻易获取,每次调用都不一样,长度是固定的值0x24,outputBuffer也很关键,返回的东西就存在里面,第一次调用长度固定0x3c,allocate长度位于返回buffer最后一个字节,由一系列奇怪的计算获得。第二次传入的参数也就是allocateHeap的长度。

      第一个参数Filehandle,由CreateFile返回,看到函数调用关系,每次调用DeviceIoControlFile之前都有CreateFile操作,理所应当的觉得这个参数由之前的createFile决定,但是动态分析的时候发现并不是这样,CreateFIle并没有返回句柄,而且zwDeviceIoControlFile用的是一个全局变量0x3c,这就很奇怪了,那要CreateFIle函数有什么用,全程都没用到。尝试nop掉其中所有对CreateFile的调用,程序居然能够正常出结果!猜测:第一个参数是一个固定的数值0x3c。

      于是准备开始写自己的第一版程序,首先是工具,直接用WIN10上面VS2015写出来的程序被报错:不是有效的win32应用程序,于是在设置IDE的时候遇到了一连串的问题,不详细讲了只大概列出来:

    • API函数未定义
    • API头文件找不到
    • API符号解析出错,有头文件没有实现,也就是说缺失lib
    • 缺失xp工具集
    • 找不到dll
    • 缺失lib【最后去偷了一个lib居然成了】
    • ...

      第一版程序大概就实现了调用zwDeviceIoControlFile,但是!重点!但是!我没有实现createFile,因为我觉得它没用啊,没用我为什么要实现,但发现调用了之后outputBuffer啥都没有你说气人不气人,这个程序不能在win10上跑,所以只能用OD调试,最开始以为是PIO_STATUS_BLOCK的错误,因为我偷懒传递了个null,但后来发现并不是这样,我坚决不加createFile上去,因为在loadLibrabry、getProcAddress之后就直接到了allocateAndGetTcpExTableFromStack(),期间也没有机会调用这个函数,我把他nop之后能够执行说明他并没有什么亂用。

      后来经过一系列的机缘巧合,我不小心在createFile里面打了一个断点,然后惊人的发现在loadLibrary的时候居然执行了这个函数,而且全局变量0x3c就是在这个时候赋值的(以前看到loadLibrary之后该变量地址就是0x3c坚定的认为他是一个死值),然后手写了一个createFile返回handle供ntDeviceIoControlFile调用就成功返回了。

      返回的Tcp表是乱序的,api里用一个qsort进行排序,觉得没必要,想着能得到pid和port就行了还要啥自行车啊,没想到埋下了祸根。

      事故发生的时候,我刚把Udp的部分写完,原理和Tcp类似,获取pid的算法不一样。

      

      输出Tcp时候pid和port都是去TcpTable里面找,但是输出Udp的时候pid是在Tcp里找的意思是和Tcp输出时的pid一样,port是在UdpTable里找的。这个时候因为他的是排过序的,我的没有排过序,所以我的程序Udp输出的pid和port对应与他的不一样。

      又是机缘巧合之下发现IDE可以用来分析dll,于是赶紧拖进去看看cmp函数怎么写的

      

    int __cdecl CompareTcp6Row(int a1, int a2)
    {
      int result; // eax
      int v3; // eax
      int v4; // ecx
      int v5; // esi
      int v6; // esi
      int v7; // edi
    
      result = memcmp((const char *)a1, (const char *)a2, 16);
      if ( !result )
      {
        v3 = *(_DWORD *)(a1 + 16);
        v4 = *(_DWORD *)(a2 + 16);
        if ( v3 != v4 )
          return v3 - v4;
        v5 = ntohs(*(_WORD *)(a1 + 20));
        v6 = v5 - ntohs(*(_WORD *)(a2 + 20));
        if ( v6 )
          return v6;
        result = memcmp((const char *)(a1 + 24), (const char *)(a2 + 24), 16);
        if ( !result )
        {
          v3 = *(_DWORD *)(a1 + 40);
          v4 = *(_DWORD *)(a2 + 40);
          if ( v3 != v4 )
            return v3 - v4;
          v7 = ntohs(*(_WORD *)(a1 + 44));
          result = v7 - ntohs(*(_WORD *)(a2 + 44));
        }
      }
      return result;
    }
    int __cdecl CompareUdp6Row(int a1, int a2)
    {
      int result; // eax
      int v3; // eax
      int v4; // ecx
      int v5; // edi
    
      result = memcmp((const char *)a1, (const char *)a2, 16);
      if ( !result )
      {
        v3 = *(_DWORD *)(a1 + 16);
        v4 = *(_DWORD *)(a2 + 16);
        if ( v3 == v4 )
        {
          v5 = ntohs(*(_WORD *)(a1 + 20));
          result = v5 - ntohs(*(_WORD *)(a2 + 20));
        }
        else
        {
          result = v3 - v4;
        }
      }
      return result;
    }

      其实这个时候我并没有什么闲心看他,因为我发现这个秘密的时候我也大胆推测得差不多了,知道现在我也没有闲心看他。

      大胆推测:tcp表按照port升序,udp表首先前四字节升序,再按port升序,这样有一个疑问

      当Udp表规模比Tcp表大的时候,取到的pid值其实已经超出了tcpTable的有效区域,事实也就是这样

      

      那些6553646和0就是垃圾值。一度怀疑fport本身算法有问题。

      附一张自己的程序运行结果:

      

      以及源代码:

      

      1 #include<iostream>
      2 #include<Windows.h>
      3 #include<WinBase.h>
      4 #include<ntstatus.h>
      5 #include<winternl.h>
      6 #include<psapi.h>
      7 
      8 using namespace std;
      9 HANDLE pH;
     10 int TcpCnt;
     11 int UdpCnt;
     12 
     13 typedef struct _TcpTable {
     14     int v1, v2, v3, v4, v5, v6;
     15 }TcpTable;
     16 
     17 typedef struct _UdpTable {
     18     int v1, v2, v3;
     19 }UdpTable;
     20 
     21 int DtoX(int value) {
     22     return (((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) |
     23         ((value & 0x00FF0000) >> 8) |
     24         ((value & 0xFF000000) >> 24)) >> 16;
     25 }
     26 
     27 int cmpTcp(const void* v1, const void* v2) {
     28     int a1 = DtoX((*(TcpTable*)v1).v3);
     29     int a2 = DtoX((*(TcpTable*)v2).v3);
     30     if (a1 < a2)
     31         return -1;
     32     else
     33         return 1;
     34 }
     35 
     36 int cmpUdp(const void* v1, const void* v2) {
     37     if ((const int)((*(UdpTable*)v1).v1) < (const int)((*(UdpTable *)v2).v1)) {
     38         return 1;
     39     }
     40     if ((const int)((*(UdpTable*)v1).v1) > (const int)((*(UdpTable *)v2).v1)) {
     41         return -1;
     42     }
     43     int a1 = DtoX((*(UdpTable*)v1).v2);
     44     int a2 = DtoX((*(UdpTable*)v2).v2);
     45     if (a1 < a2) {
     46         return -1;
     47     }
     48     else {
     49         return 1;
     50     }
     51 }
     52 
     53 void GetTableFromStack(int * inputBuffer, int * outputBuffer, int outputBufferLength) {
     54     HANDLE eventhandle = CreateEvent(0, 1, 0, 0);
     55     if (eventhandle == NULL) {
     56         printf("Create event error");
     57         return;
     58     }
     59     IO_STATUS_BLOCK iostatus_block;
     60     NtDeviceIoControlFile(pH, eventhandle, 0, 0, &iostatus_block, 0x120003, inputBuffer, 0x24, outputBuffer, outputBufferLength);
     61     CloseHandle(eventhandle);
     62 }
     63 
     64 int * AllocateAndGetUdpTable() {
     65     int input1[9] = { 0x401, 0, 0x200, 0x100, 1, 0, 0, 0, 0 };
     66     int input2[9] = { 0x401, 0, 0x200, 0x100, 0x102, 0, 0, 0, 0 };
     67     int output1[5] = { 0 };
     68     GetTableFromStack(input1, output1, 0x14);
     69     UdpCnt = output1[4];
     70     int TableSize = ((UdpCnt+ 0xA) * 3 + 3) * 4 - 4;
     71     int * ptrToTable = (int *)malloc(TableSize);
     72     GetTableFromStack(input2, ptrToTable, TableSize);
     73     //qsort();
     74     return ptrToTable;
     75 }
     76 
     77 int * AllocateAndGetTcpTable() {
     78     int input1[9] = { 0x400, 0, 0x200, 0x100, 1, 0, 0, 0, 0 };
     79     int input2[9] = { 0x400, 0, 0x200, 0x100, 0x102, 0, 0, 0, 0 };
     80     int output1[15] = { 0 };
     81     GetTableFromStack(input1, output1, 0x3c);
     82     TcpCnt = output1[14];
     83     int TableSize = (TcpCnt + 0xA) * 24 + 0xc - 4;
     84     int * ptrToTable = (int *)malloc(TableSize);
     85     GetTableFromStack(input2, ptrToTable, TableSize);
     86     //qsort();
     87     return ptrToTable;
     88 }
     89 
     90 void OpenTcpDriver() {
     91     IO_STATUS_BLOCK ioStB;
     92     PCWSTR sourceString = L"\Device\Tcp";
     93     UNICODE_STRING DestinationString;
     94     RtlInitUnicodeString(&DestinationString, sourceString);
     95     OBJECT_ATTRIBUTES objAtt;
     96     objAtt.ObjectName = &DestinationString;
     97     objAtt.Length = 24;
     98     objAtt.RootDirectory = 0;
     99     objAtt.Attributes = 64;
    100     objAtt.SecurityDescriptor = 0;
    101     objAtt.SecurityQualityOfService = 0;
    102     NtCreateFile(&pH, 0x20000000u, &objAtt, &ioStB, 0, 0x80u, 3u, 3u, 0, 0, 0);
    103     return;
    104 }
    105 
    106 void showInformation(int pid, int port) {
    107     char ProcessName[28] = { '0' };
    108     char Path[409] = { '0' };
    109     char PathA[409] = { '0' };
    110     HMODULE hModule = 0;
    111     HMODULE hModule2 = 0;
    112     LPDWORD cbNeeded = 0;
    113     LPDWORD cbNeeded2 = 0;
    114     HANDLE processH = OpenProcess(0x410u, 0, pid);
    115     if (processH) {
    116         if (EnumProcessModules(processH, &hModule, 0x28u, (LPDWORD)&cbNeeded)) {
    117             if (GetModuleBaseNameA(processH, hModule, (LPSTR)ProcessName, 0x78u)) {
    118                 HANDLE processH2 = OpenProcess(0x410u, 0, pid);
    119                 if (processH2) {
    120                     if (EnumProcessModules(processH2, &hModule, 4096, (LPDWORD)&cbNeeded2)) {
    121                         GetModuleFileNameEx(processH2, hModule2, (LPTSTR)Path, 260);
    122                     }
    123                     CloseHandle(processH2);
    124                 }
    125             }
    126         }
    127         else {
    128             CloseHandle(processH);
    129         }
    130     }
    131     WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, (LPCWSTR)Path, -1, (LPSTR)PathA, 409, NULL, NULL);
    132     cout << " pid: " << pid << " port: " << port << " ProcessName: " << ProcessName << " Path: " << PathA << endl;
    133 }
    134 
    135 int main() {
    136     OpenTcpDriver();
    137     int * pToTcpTable = AllocateAndGetTcpTable();
    138     qsort(pToTcpTable, TcpCnt, 24, cmpTcp);
    139     int index = 0;
    140     cout << "TCP information:" << endl;
    141     while (TcpCnt--) {
    142         int pid = pToTcpTable[index + 5];
    143         int port = DtoX(pToTcpTable[index + 2]);
    144         showInformation(pid, port);
    145         index += 6;
    146     }
    147     int * pToUdpTable = AllocateAndGetUdpTable();
    148     qsort(pToUdpTable, UdpCnt, 12, cmpUdp);
    149     index = 0;
    150     int index2 = 0;
    151     cout << "Udp information:" << endl;
    152     while (UdpCnt--) {
    153         int pid = pToTcpTable[index + 5];
    154         int port = DtoX(pToUdpTable[index2 + 1]);
    155         showInformation(pid, port);
    156         index2 += 3;
    157         index += 6;
    158     }
    159     return 0; 
    160 }

      

  • 相关阅读:
    javascript里面this机制的几个例子
    把List<string>集合,编程string,并以“,”号分割
    比较集合List<T>集合,前后多了哪些数据,少了哪些数据Except
    c# Web.config中 windows连接数据库
    MVC之图片验证码
    匿名函数-简单实例
    c# 如何找到项目中图片的相对路径
    MVC下 把数据库中的byte[]值保存成图片,并显示在view页面
    MVC下form表单一次上传多种类型的图片(每种类型的图片可以上传多张)
    关于Visual Studio未能加载各种Package包的解决
  • 原文地址:https://www.cnblogs.com/rlee063/p/8632096.html
Copyright © 2011-2022 走看看