现在的位置: 首页 > 综合 > 正文

编程修改BIN等二进制文件

2013年12月01日 ⁄ 综合 ⁄ 共 2894字 ⁄ 字号 评论关闭

在此之前,我曾经写过,把铃声,图片等资源转化为数组数据,也曾经写过把数组数据转为图片和声音.在某篇文章中,也曾经写了从BIN文件中提取图片等信息.这些都是利用编程的手段访问解析二进制文件.都是对二进制文件进行操作.

我们获得的手机或者其他嵌入式设备的软件,常常都是一些扩展名为BIN的文件,这些文件就是二进制文件.对这类二进制文件的写操作需要慎之又慎,一着出错,就可能导致BIN文件再也无法使用.

我曾经写了一个修改软件版本号的工具,主要用来修改MTK软件的版本号.一般来说,为了软件管理和维护方便,我们每次修改发布新软件,都应该相应的升级软件版本号,有时软件版本号忘记了升级,往往需要重新NEW一个软件,费时又费力.还有就是有一些客户,软件相同,也使用相同的SP,只是客户USERID不同,这时也可以使用版本管理工具根据原始软件修改替换ID生成新的客户软件.所以研究BIN,修改BIN,提高工作效率,对于现阶段减轻软件工程师负担还是一些意义的.

闲话就不说了,主要算法就是:

1.把BIN文件读入内存数组中主要使用CFILE类的read方法

2.查找需要替换的字串,主要使用memcmp

3.替换新的字串,主要使用memcpy

4.把替换后的数组写入文件,主要使用CFILE类的write方法

 

CFile的方法直接调用,不再赘述.

查找替换字串的函数如下,由于二进制数据操作,无法使用strlen获取长度,所以必须提供长度,由于BIN文件有对齐处理,如果使用不同长度字串替换时如果不考虑对齐会导致BIN文件失效,所以限制OLD和NEW串必须长度一样,当然如果要使用长度不等的字串互相替换也是可以的,一是考虑位的对齐,二是考虑替换后不超出14M:
int StrReplace(char *basestr, int basestrlen, char *oldstr, int oldstrlen, char *newstr, int newstrlen)
{
int count = 0;

char *p=basestr;
if (oldstrlen != newstrlen)
{
return -1;
}
if(basestrlen < oldstrlen)
{
return -2;
}

while(basestrlen-- > 0)
{
if(memcmp(p,oldstr,oldstrlen) != 0)
{
p++;
}
else
{
memcpy(p,newstr,newstrlen);
p += newstrlen;
count ++;
}
}
return count>0?0:1;
}

为该程序创建一个对话框,包括三个EDIT控件,第一个EDIT显示文件名字,第二个显示要替换的字串,第三个显示新的字串,分别绑定三个CString变量,m_FileName , m_OldStr, m_NewStr,三个按钮,分别对事件打开OnOK(), 替换OnOk2(),和退出按钮:

按钮事件分别为:

 //打开文件

 void CModifyBINDlg::OnOK()
{
// TODO: Add extra validation here
static char BASED_CODE szFilter[] = "All Files(*.*)|*.*|Bitmap Files (*.bmp)|*.bmp||";
CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST| OFN_HIDEREADONLY, szFilter, NULL);

CString strPath,strText; //声明变量
if(dlg.DoModal() == IDOK) //判断是否按下"打开"按钮
{
strPath = dlg.GetPathName(); //获得文件路径
CModifyBINDlg::SetWindowText(strPath); //显示文件路径
UpdateData(TRUE);
m_FileName = strPath;
UpdateData(FALSE);
}

//CDialog::OnOK();
}

 //替换字串并生成新文件

void CModifyBINDlg::OnOk2()
{
// TODO: Add your control notification handler code here
CString olds, news;
unsigned char *buffer;
long filelen;
CString newfilename;

UpdateData(TRUE);
olds = m_OldStr;
news = m_NewStr;
UpdateData(FALSE);

CFile file(m_FileName,CFile::modeRead|CFile::typeBinary); //打开文件
filelen = file.GetLength();

buffer = (unsigned char *)malloc((filelen+1)*sizeof(char));

file.Read(buffer,file.GetLength());
file.Close(); //关闭文件
if (olds.GetLength() != news.GetLength())
{
AfxMessageBox("查找字串与新字串长度不等");
}
if (StrReplace((char *)buffer, filelen, (char *)(LPCTSTR)olds, olds.GetLength(),
(char *)(LPCTSTR)news, news.GetLength()) != 0)
{
free(buffer);
AfxMessageBox("没找到替换字串");
return;
}
CFile file2;
file2.Open(GetPath(m_FileName)+"new_"+GetFileName(m_FileName),
CFile::modeWrite|CFile::modeCreate|CFile::typeBinary);
file2.Seek(0,CFile::begin);
file2.Write(buffer,filelen);
file2.Close();
AfxMessageBox("替换完成");
free(buffer);
}

 在替换生成新BIN时,调用了两个解析路径获得文件名和目录的函数:

//从路径中分离文件名:

CString GetFileName(CString pathname)
{
for( int i=pathname.GetLength()-1; i>=0; i-- )
{
if( pathname[i]=='//' )
{
//这里倒着查,查到倒数第一个反斜框,退出
break;
}
}
return pathname.Mid( i+1 );
}
//从路径中分离路径名(去除文件名):

CString GetPath(CString pathname)
{
int i = 0, j;
while( i<pathname.GetLength() )
{
if( pathname[i]=='//' )
{
//这里偷一下懒,反正咱的机子速度快,从第一个反斜杠找到最后一个,且取最后一个
j = i;
}
i++;
}
return pathname.Left( j+1 );
}

 

抱歉!评论已关闭.