1.4 编程判断主机
字节序是更进一步掌握字节序的方式,本小节给出两种对主机的字节序进 行判断的方式。 1.4.1 字节序相关函数 在 TCP/IP 网络编程中会涉及关于字节序的函数, TCP/IP 协议中传递数据是以网络字节 序进行传输的,网络字节序是指网络传输相关协议所规定的字节传输的顺序, TCP/IP 协议所 使用的网络字节序与大尾方式相同。而主机字节序包含大尾方式与小尾方式,因此在进行网 络传输时会进行相应的判断,如果主机字节序是大尾方式则无需进行转换即可传输,如果主 机字节序是小尾方式则需要转换成网络字节序(也就是转换成大尾方式)然后进行传输。 常用的字节序涉及的函数有如下几个: u_short htons(u_short hostshort); u_long htonl(u_long hostlong); u_short ntohs(u_short netshort); u_long ntohl(u_long netlong); 在这 4 个函数中,前两个是将主机字节序转换成网络字节序,后两个是将网络字节序转 换为主机字节序。关于更多的字节序的函数可参考 MSDN。 1.4.2 编程判断主机字节序 “编程判断主机字节序”是很多杀毒软件公司或者安全开发职位的一道面试题,因为这个 题目比较基础。通过前面的知识,相信读者能够很容易地实现该程序。这里给出笔者自己对 于该题目的实现方法。笔者认为,完成该题目有两种方法,第一种方法是“取值比较法”,第 二种方法是“直接转换比较法”。 |
| 1.取值比较法 所谓取值比较法,是首先定义一个 4 字节的十六进制数。因为使用调试器查看内存最直观 的就是十六进制,所以定义十六进制数是一个操作起来比较直观的方法。而后通过指针方式取 出这个十六进制数在“内存”中的某一个字节,最后与实际数值中相对应的数进行比较。由于 字节序的原因,内存中的某字节与实际数值中对应的字节可能不相同,这样就可以确定字节序了。 代码如下: #include <windows.h> #include <stdio.h> int main(int argc, char *argv[]) { DWORD dwSmallNum = 0x01020304; if ( *(BYTE )&dwSmallNum == 0x04 ) { printf("Small Sequence. \r\n"); } else { printf("Big Sequence. \r\n"); } return 0; } 以上代码中,定义了 0x01020304 这个十六进制数,其在小尾方式内存中的存储顺序为 04 03 02 01。取(BYTE )&dwSmallNum 内存中的低地址位的值,如果是小尾方式的话,那 么低地址存储的值为 0x04;如果是大尾方式的话,则低地址存储的值为 0x01。 注意: 这段代码的关键就是(BYTE *)&dwSmallNum 取出来的值。 2.直接转换比较法 所谓直接转换比较法,是利用字节序转换函数将所定义的值进行转换,然后用转换后的 值与原值进行比较。如果原值与转换后的值相同,说明是大尾方式,否则为小尾方式。 代码如下: #include <stdio.h> #include <winsock2.h> #pragma comment(lib, "ws2_32") int main(int argc, char *argv[]) { DWORD dwSmallNum = 0x01020304; if ( dwSmallNum == htonl(dwSmallNum) ) { printf("Small Sequence. \r\n"); } else { printf("Big Sequence. \r\n"); } return 0; } | |
| 13 第1章 数据的存储及表示形式 |
| 这种方式比较直接,其前提是网络字节序是固定的,就是大尾方式。因为是比较,所以 就要有一个参照物。如果原值转换后的结果与原值相同,就说明该主机是大尾方式存储,反 之则是小尾方式。 1.5 总结 本章对内存中存储基础数据的方式进行了阐述,并且在最后部分介绍了如何使用 OD 调 试器来查看内存中的数据。在学习编程时,都会从数据类型开始介绍,不同的数据类型都是 以二进制的方式存储在内存中的,只是它们存储的方式不同,或者是存储的宽度不同。在我 们学习逆向时,也首先讲解了数据的基础及数据的存储方式。