怎么用c语言解析二进制文件

Python014

怎么用c语言解析二进制文件,第1张

//ver:1

//resv1:0

//signature:CUC

//type:69

//no:5

//resv2:0

//seq:4

//length:56

//int2,1

//int2,2

//int1,1

//int4,30

//int1,1

//int1,7

//str,beijing

//int2,1

//int2,4

//int1,1

//int4,60

//int1,1

//int1,7

//str,tianjin

//int4,80

//二进制文件b.bin是:

//00000000h: 01 43 55 43 45 00 05 00 00 00 00 04 00 00 00 38

//00000010h: 00 01 00 02 01 00 00 00 1E 01 07 62 65 69 6A 69

//00000020h: 6E 67 00 01 00 04 01 00 00 00 3C 01 07 74 69 61

//00000030h: 6E 6A 69 6E 00 00 00 50

#pragma comment(lib,"ws2_32")

#include <stdio.h>

#include <winsock2.h>

#pragma pack(push,1)

struct _D {

    char  ver

//  char  resv1

    char  signature[3]

    char  type

    short no

    char  resv2

    int   seq

    int   length

    short int2_0

    short int2_1

    char  int1_0

    int   int4_0

    char  int1_1

    char  int1_2

    char  str_0[7]

    short int2_2

    short int2_3

    char  int1_3

    int   int4_1

    char  int1_4

    char  int1_5

    char  str_1[7]

    int   int4_2

} d

#pragma pack(pop)

FILE *f

int main() {

    f=fopen("b.bin","rb")

    if (NULL==f) {

        printf("Can not open file b.bin!\n")

        return 1

    }

    fread(&d,sizeof(struct _D),1,f)

    fclose(f)

    printf("ver:%d\n"        ,d.ver)

    printf("resv1:0\n")

    printf("signature:%.3s\n",d.signature)

    printf("type:%d\n"       ,d.type)

    printf("no:%hd\n"        ,ntohs(d.no))

    printf("resv2:%d\n"      ,d.resv2)

    printf("seq:%d\n"        ,ntohl(d.seq))

    printf("length:%d\n"     ,ntohl(d.length))

    printf("int2_0:%hd\n"    ,ntohs(d.int2_0))

    printf("int2_1:%hd\n"    ,ntohs(d.int2_1))

    printf("int1_0:%d\n"     ,d.int1_0)

    printf("int4_0:%d\n"     ,ntohl(d.int4_0))

    printf("int1_1:%d\n"     ,d.int1_1)

    printf("int1_2:%d\n"     ,d.int1_2)

    printf("str_0:%.7s\n"    ,d.str_0)

    printf("int2_2:%hd\n"    ,ntohs(d.int2_2))

    printf("int2_3:%hd\n"    ,ntohs(d.int2_3))

    printf("int1_3:%d\n"     ,d.int1_3)

    printf("int4_1:%d\n"     ,ntohl(d.int4_1))

    printf("int1_4:%d\n"     ,d.int1_4)

    printf("int1_5:%d\n"     ,d.int1_5)

    printf("str_1:%.7s\n"    ,d.str_1)

    printf("int4_2:%d\n"     ,ntohl(d.int4_2))

    return 0

}

//ver:1

//resv1:0

//signature:CUC

//type:69

//no:5

//resv2:0

//seq:4

//length:56

//int2_0:1

//int2_1:2

//int1_0:1

//int4_0:30

//int1_1:1

//int1_2:7

//str_0:beijing

//int2_2:1

//int2_3:4

//int1_3:1

//int4_1:60

//int1_4:1

//int1_5:7

//str_1:tianjin

//int4_2:80

//

代码示例

很简单的

配置文件 微软有抓们的一套解析函数

INI文件是Windows系统中一类比较重要的文件,通常用来存放系统或者应用程序的配置信息,以方便系统或者应用 程序在初始化时再次读入。比如Windows系统中的配置文件win.ini和system.ini,它们就主要存放系统启动或用户登陆时的系统信息。这 项功能在方便了系统配置的同时,也为非法程序的自动运行提供了可乘之机。显然,这类文件的重要性应该引起我们的重视。但是对于这样的ini文件的读写操作 却与普通文本文件有着种种的不同,尤其体现在编程实现上。笔者曾经尝试用手动更改的方法在文件中加入一些项,使得自己的程序能够在初始化时自动运行,但是 却没有成功,最后还是藉由编程的方法来实现了。这里主要涉及到一些API函数,而这些函数又往往不被人们所熟知,本文的任务就是在介绍这些函数的同时,用 简单的程序作了示例,下面我们言归正传。

先来看几个往配置文件中写入信息的函数:

(1)WritePrivateProfileSection()用来在ini文件中直接向指定区域写入键和值的信息,其原型如下:

BOOL WritePrivateProfileSection(

LPCTSTR lpAppName, // 指向指定字段字符串

LPCTSTR lpString, // 指向要写入的键与值字符串

LPCTSTR lpFileName // 指向文件名称字符串,如果不包含完整路径,则在windows目录下创建

)

用法示例:

WritePrivateProfileSection(_T(“windows”),_T(“load=c:\\winnt\\notepad.exe”),_T(“c:\\winnt\\win.ini”))

(2)WritePrivateProfileString()与上一个函数的不同点在于其将键和值分开了,原型如下:

BOOL WritePrivateProfileString(

LPCTSTR lpAppName, // 指向指定字段的字符串

LPCTSTR lpKeyName, // 指向指定键的字符串

LPCTSTR lpString, // 指向指定值的字符串

LPCTSTR lpFileName // 指向文件名称字符串

)

用法示例:

WritePrivateProfileString(_T(“windows”),_T(load”)_T(“c:\\winnt\\notepad.exe”),_T(“c:\\winnt\\win.ini”))

(3)WritePrivateProfileStruct()与前面两个的不同在于文件尾有校验和,原型如下:

BOOL WritePrivateProfileStruct(

LPCTSTR lpszSection, //指向指定字段的字符串

LPCTSTR lpszKey, //指向指定键的字符串

LPVOID lpStruct, //指向存放要加入的数据的缓冲区,如果为NULL,则删除键

UINT uSizeStruct, //缓冲区大小,以字节为单位

LPCTSTR szFile //以零结尾的文件名称字符串,如果为空,则向win.ini写入

)

用法示例:

WritePrivateProfileStruct(_T(“windows”),_T(“load”),pBuffer,sizeof(pBuffer),_T(“c:\\winnt\\win.ini”))

(4)还有两个函数,是专门用来向win.ini文件写入的,函数原型如下:

BOOL WriteProfileSection(

LPCTSTR lpAppName, //指向指定字段的字符串

LPCTSTR lpString //指向指定值的字符串

)

BOOL WriteProfileString(

LPCTSTR lpAppName, //指向指定字段的字符串

LPCTSTR lpKeyName, //指向指定键的字符串

LPCTSTR lpString //指向指定值的字符串

)

下面来看几个对应的从ini文件获取信息的API函数,上面已经说得很详细了,这里只说其中两个:

DWORD GetPrivateProfileString(

LPCTSTR lpAppName, //指向指定字段的字符串

LPCTSTR lpKeyName, //指向键的字符串

LPCTSTR lpDefault, //如果INI文件中没有前两个参数指定的字段名或键名,则将此值赋给变量

LPTSTR lpReturnedString, //存放INI文件中值的目的缓存区

DWORD nSize, //目的缓冲区的大小,以字节为单位

LPCTSTR lpFileName //指向INI文件名称的字符串

)

UINT GetPrivateProfileInt(

LPCTSTR lpAppName, //指向指定字段的字符串

LPCTSTR lpKeyName, //指向键的字符串

INT nDefault, //如果INI文件中没有前两个参数指定的字段名或键名,则将此值赋给变量

LPCTSTR lpFileName //指向INI文件名称的字符串

)

程序示例1: 我们在这里建立了一个应用程序“App Name”,并且使用了一个INI文件“appname.ini”,在此INI文件中,我们写入如下内容:

[Section1]

FirstKey = It all worked out okay.

SecondKey = By golly, it works.

ThirdKey = Another test.

代码分析如下:

#include <stdio.h>

#include <windows.h>

//主函数

main()

{

//定义局部

CHAR inBuf[80]

HKEY hKey1, hKey2

DWORD dwDisposition

LONG lRetCode

// 试图创建INI文件的键值

lRetCode = RegCreateKeyEx ( HKEY_LOCAL_MACHINE,

"SOFTWARE\\Microsoft\\Windows NT

\\CurrentVersion\\IniFileMapping\\appname.ini",

0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,

NULL, &hKey1,

&dwDisposition)

//判断是否出错

if (lRetCode != ERROR_SUCCESS){

printf ("Error in creating appname.ini key\n")

return (0)

}

//试图设置一个节区的值

lRetCode = RegSetValueEx ( hKey1,

"Section1",

0,

REG_SZ,

"USR:App Name\\Section1",

20)

//判断是否出错

if (lRetCode != ERROR_SUCCESS) {

printf ( "Error in setting Section1 value\n")

return (0)

}

//试图创建一个应用名称键值

lRetCode = RegCreateKeyEx ( HKEY_CURRENT_USER,

"App Name",

0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,

NULL, &hKey2,

&dwDisposition)

//判断是否出错

if (lRetCode != ERROR_SUCCESS) {

printf ("Error in creating App Name key\n")

return (0)

}

//强制系统重新读取映射区的内容到共享内存中,以便于将来对应用程序的调用可//以找到它,而不需要重新启动系统

WritePrivateProfileStringW( NULL, NULL, NULL, L"appname.ini" )

//向INI文件中添加一些键值

WritePrivateProfileString ("Section1", "FirstKey",

"It all worked out okay.", "appname.ini")

WritePrivateProfileString ("Section1", "SecondKey",

"By golly, it works.", "appname.ini")

WritePrivateProfileSection ("Section1", "ThirdKey = Another Test.",

"appname.ini")

//测试一下添加的正确性

GetPrivateProfileString ("Section1", "FirstKey",

"Bogus Value: Get didn't work", inBuf, 80,

"appname.ini")

printf ("%s", inBuf)

return(0)

}

程序示例2:通过修改win.ini中的字段[windows]中的键load或run,或者是为system.ini中的字段[boot]中的键 shell增加值,可以达到设置程序自动运行的目的。假设我们要自动运行notepad.exe,修改后的win.ini或system.ini文件象这 样就可以:

win.ini

[windows]

load=c:\winnt\notepad.exe

run=c:\winnt\notepad.exe

system.ini

[boot]

shell=c:\winnt\explorer.exe c:\winnt\notepad.exe

注意:system.ini文件的修改要特别注意,如果你单纯改成shell=c:\winnt\notepad.exe,则不能首先运行 explorer.exe,很明显你将看不到桌面和任务栏,呵呵,笔者在做实验时就曾因为粗心造成了这样的后果,不过不用害怕,只要你用我们下面提供的程 序,将它修改过来就可以了,默认时,系统在system.ini中的[boot]下是shell=c:\winnt\explorer.exe。很多非法 程序就是通过修改这两个文件来达到自启动的目的的。

下面这个程序可以在附书光盘中找到,名称为“AutoPlay”,使用VC++6.0写成,核心程序源代码如下:

void CAutoRunDlg::OnBrowse()

{

//只浏览exe文件

CfileDialog fileDlg(TRUE,_T("EXE"),_T("*.exe"),OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,(_T("Executable Files (*.exe) |*.exe ||")))//显示打开文件的对话框

//当操作者选择OK时,程序取得选择文件的全路径名(包括文件的路径及文件名称),并将相应的数值传输给相关的控件变量。

if(fileDlg.DoModal()==IDOK)

{

m_strFileName=fileDlg.GetPathName()

//向将变量中的数值传输给控件显示出来。

UpdateData(FALSE)

}

}

void CAutoRunDlg::OnApply()

{

//更新数据

UpdateData(TRUE)

//写入ini文件

LPCTSTR filename

filename=m_strFileName

WritePrivateProfileString(_T("windows"),_T("load"),filename,_T("c:\\winnt\\win.ini"))

}

您如果要更改system.ini,可以将WritePrivateProfileString(_T("windows"),_T("load"),filename,_T("c:\\winnt\\win.ini"))

改为 WritePrivateProfileString(_T("boot"),_T("shell"),filename,_T("c:\\winnt \\system.ini"))并且在输入文件名时输入c:\winnt\explorer.exe c:\winnt\notepad.exe。

写到这里,本文的意图基本达到,如果您可以把某些代码亲自实现,相信读者会有比较大的收获。