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 }
原文链接: https://www.cnblogs.com/rlee063/p/8632096.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/270961
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!