Fport逆向分析以及C++实现

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

Fport逆向分析以及C++实现

首先将文件拖入IDA分析

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

Fport逆向分析以及C++实现

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

Fport逆向分析以及C++实现

GetProcessHeap 返回当前进程堆句柄。

Fport逆向分析以及C++实现

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

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

Fport逆向分析以及C++实现

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

进入AllocateAndGetTcpExTableFromStack()

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

Fport逆向分析以及C++实现Fport逆向分析以及C++实现Fport逆向分析以及C++实现

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

Fport逆向分析以及C++实现

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

Fport逆向分析以及C++实现

看上去这是一个和硬件打交道的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的算法不一样。

Fport逆向分析以及C++实现

输出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的有效区域,事实也就是这样

Fport逆向分析以及C++实现

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

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

Fport逆向分析以及C++实现

以及源代码:

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 }

原文链接: https://www.cnblogs.com/rlee063/p/8632096.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/270961

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月14日 下午9:36
下一篇 2023年2月14日 下午9:38

相关推荐