|
楼主 |
发表于 2011-8-1 18:22:41
|
显示全部楼层
回复【462楼】electron_love
-----------------------------------------------------------------------
这么久了还被挖出来,看来很多人还的确是为产品加密犯愁过....
首先感谢462楼激_情洋溢的长篇回复。
其实你提的箱子和钥匙理论,基本上可以这样去理解。至于钥匙放到另一个箱子内,文中确实也提到过,有一个全局校验码检测,如果加密的地方被人改动过或未进入某段代码而修改了变量想瞒天过海,也是要触发机关的,这也是对钥匙的一种监督。
其实这种方法后期改动BIN很麻烦,因为要量产,所以不得不借助上位机辅助改动程序BIN,至于改动方法就五花八门了,但要与你单片机编译及变量定义位置紧密结合。
以下代码为早期一个4K代码量的小产品对BIN进行加密的一段上位机代码,程序先将HEX转换成BIN文件,再用指定方式对BIN文件进行修改,由于此单片机代码量较小,思路比较简单。从简单程序开始更容易理解些....
上位机软件为BCB,你也可以稍加修改使用VC或VB编程。你再和下载软件关联起来,整个过程就只需你点一个键而已。
HEX转为BIN文件函数内容;注:未处理校验码
---------flywater
void HexToBin()
{
String sDataStr,sTemp;
int nMemLines=0; //HEX文件总段数;
int nByteLen=0; //有效数据字节数;
int nDataAddr=0; //偏移地址;
int nDataType=0; //类型:00 -数据记录,01-文件结束记录,02-扩展段地址记录,04-扩展线性地址记录
unsigned char sBuffer[100];
int iFileHandle;
Memo4->Lines->Clear();
Memo4->Lines->LoadFromFile(current_dir+"\\Hub.hex");
//读入后转换成BIN格式;
nMemLines=Memo4->Lines->Count;
//创建BIN文件(flash)
if(FileExists(current_dir+"\\FlashOk.bin"))
{
try
{
DeleteFile(current_dir+"\\FlashOk.bin");
}
catch(...)
{
}
iFileHandle = FileCreate(current_dir+"\\FlashOk.bin");
}
else
{
iFileHandle = FileCreate(current_dir+"\\FlashOk.bin");
}
for (int i=0;i<nMemLines;i++) //逐行处理;
{
sDataStr=Memo4->Lines->Strings;
sTemp=sDataStr.SubString(1,1);
if(sTemp!=":") //此行的开始;
{
FileClose(iFileHandle);
Application->MessageBoxA("HEX文件格式有误,请检查!","提示",64);
return;
}
sDataStr=sDataStr.Delete(1,1);
sTemp=sDataStr.SubString(1,2);
sTemp="0x"+sTemp.Trim(); //取出有效字节个数;
try
{
nByteLen=StrToInt(sTemp);
}
catch(...)
{
//数据错误,
FileClose(iFileHandle);
Application->MessageBoxA("数据错误,请检查!","提示",64);
return;
}
//取出偏移量;
sDataStr=sDataStr.Delete(1,2);
sTemp=sDataStr.SubString(1,4);
sTemp="0x"+sTemp.Trim();
try
{
nDataAddr=StrToInt(sTemp);
}
catch(...)
{
//数据错误,
FileClose(iFileHandle);
Application->MessageBoxA("数据错误,请检查!","提示",64);
return;
}
//取出数据类型;
sDataStr=sDataStr.Delete(1,4);
sTemp=sDataStr.SubString(1,2);
try
{
nDataType=sTemp.ToInt();
}
catch(...)
{
nDataType=0;
}
//把数据转换后入到文件缓冲中;
memset(sBuffer,0,sizeof(sBuffer));
for(int i=0;i<nByteLen;i++)
{
sDataStr=sDataStr.Delete(1,2);
sTemp=sDataStr.SubString(1,2);
sTemp="0x"+sTemp.Trim(); //取出有效字节个数;
try
{
sBuffer=(unsigned char)StrToInt(sTemp);
}
catch(...)
{
}
}
//FileSeek(iFileHandle,0,0);
FileSeek(iFileHandle,nDataAddr,0);
FileWrite(iFileHandle, sBuffer, nByteLen);
}
FileClose(iFileHandle);
}
//BIN修改函数内容;
void CHGBinFile()
{
int iFileHandle; //文件句柄
String sSerialString;
String sTemp;
byte sBuffer[0x2000]; //修改BIN暂存区
byte sRandData[40]; //随机数;
word nCrc16Temp=0; //CRC码暂存
//第一组校验变量;
int nDataStart1; //
int nAddCrc1=0;
//第二组校验变量;
int nDataStart2;
int nAddCrc2=0; //CRC要存放的地址;
//第三组校验变量;
int nDataStart3;
int nAddCrc3=0;
//第四组校验变量;
int nDataStart4;
int nAddCrc4=0;
//MCU ID号处理变量;
int nAddCrc5=0; //MCU ID号校验码存放位置;
byte sSerialNo[10];
byte sOkCrc[20];
memset(sOkCrc,0,sizeof(sOkCrc));
memset(sSerialNo,0,sizeof(sSerialNo));
//产品序列号处理变量;
int nProductNoAddr;
int nProductNoCrcAddr;
byte sProductNo[24];
char chTemp;
String sProductNoStr=Edit4->Text.Trim();
//取出产品序列号; //产品序列号,非MCU序列号
memset(sProductNo,0,sizeof(sProductNo));
for(int i=0;i<20;i++)
{
sTemp=sProductNoStr.SubString(1,1);
memcpy(sProductNo+i,sTemp.c_str(),1) ;
sProductNoStr=sProductNoStr.Delete(1,1);
}
//取出设定值: 把予设的各函数入口地址及校验码存放地址从EDIT中取出
try
{
nDataStart1=Edit7->Text.ToInt();
nDataStart2=Edit9->Text.ToInt();
nDataStart3=Edit11->Text.ToInt();
nDataStart4=Edit13->Text.ToInt();
nAddCrc1=Edit5->Text.ToInt();
nAddCrc2=Edit8->Text.ToInt();
nAddCrc3=Edit10->Text.ToInt();
nAddCrc4=Edit12->Text.ToInt();
nAddCrc5=Edit15->Text.ToInt();
nProductNoAddr=Edit16->Text.ToInt();
nProductNoCrcAddr=Edit17->Text.ToInt();
}
catch(...)
{
}
//取出序列号;此处为MCU的序列号
sSerialString=Edit14->Text.Trim();
if(sSerialString.Length()<7) //序列号有误;
{
Application->MessageBoxA("序列号有误,请检查!","提示",64);
return;
}
sTemp=sSerialString.SubString(1,2);
sTemp="0x"+sTemp;
sSerialString=sSerialString.Delete(1,2);
for(int i=0;i<7;i++)
{
try
{
sSerialNo=(byte)sTemp.ToInt();
}
catch(...)
{
Application->MessageBoxA("序列号有误,请检查!","提示",64);
return;
}
sTemp=sSerialString.SubString(1,2);
sTemp="0x"+sTemp;
sSerialString=sSerialString.Delete(1,2);
}
//打开BIN文件(flash)
if(!FileExists(current_dir+"\\FlashOk.bin"))
{
Application->MessageBoxA("Bin文件不存在,无法进行操作!","提示",64);
return;
}
iFileHandle = FileOpen(current_dir+"\\FlashOk.bin",fmOpenReadWrite);
//处理第二个校验:一般从0开始,中断及主程序入口函数防改
memset(sBuffer,0,sizeof(sBuffer));
FileSeek(iFileHandle,nDataStart2,0);
FileRead(iFileHandle,sBuffer,180);
nCrc16Temp=CRC16Check(sBuffer,50);
FileSeek(iFileHandle,nAddCrc2,0);
memcpy(sBuffer+60,&nCrc16Temp,2);
sBuffer[62]=sBuffer[61];
sBuffer[63]=sBuffer[60];
memcpy(sOkCrc+2,sBuffer+62,2);
FileWrite(iFileHandle,sBuffer+62,2);
//处理第三个校验:读取序列号函数防改
memset(sBuffer,0,sizeof(sBuffer));
FileSeek(iFileHandle,nDataStart3,0);
FileRead(iFileHandle,sBuffer,50);
nCrc16Temp=CRC16Check(sBuffer,50);
FileSeek(iFileHandle,nAddCrc3,0);
memcpy(sBuffer+60,&nCrc16Temp,2);
sBuffer[62]=sBuffer[61];
sBuffer[63]=sBuffer[60];
memcpy(sOkCrc+4,sBuffer+62,2);
FileWrite(iFileHandle,sBuffer+62,2);
//处理第四个校验: Mian 主函数防改
memset(sBuffer,0,sizeof(sBuffer));
FileSeek(iFileHandle,nDataStart4,0);
FileRead(iFileHandle,sBuffer,170);
nCrc16Temp=CRC16Check(sBuffer,170);
FileSeek(iFileHandle,nAddCrc4,0);
memcpy(sBuffer+60,&nCrc16Temp,2);
sBuffer[62]=sBuffer[61];
sBuffer[63]=sBuffer[60];
memcpy(sOkCrc+6,sBuffer+62,2);
FileWrite(iFileHandle,sBuffer+62,2);
//写入序列号校验码;产品序列号及以上各校验码再校验一次进行存放;
nCrc16Temp=CRC16Check(sProductNo,20);
nCrc16Temp=nCrc16Temp+sProductNo[17];
memcpy(sBuffer+60,&nCrc16Temp,2);
sBuffer[62]=sBuffer[61];
sBuffer[63]=sBuffer[60];
FileSeek(iFileHandle,nProductNoCrcAddr,0);
FileWrite(iFileHandle,sBuffer+62,2);
//随机数;将BIN内一些地方写上随机数,要从单片机编译器中将这些地方定义为空,此范例只写了一处,可根据您的情况,搞上10处!如果FLASH空余较多,每处写上几百字节或者从其它程序中搞些代码过来也可---淡定,注意程序稳定性,结束最好加上02 00 00;
FileSeek(iFileHandle,4080,0);
randomize();
for(int i=0; i<500; i++)
{
sRandData=rand() % 0xff;
}
FileWrite(iFileHandle,sRandData,16);
//处理序列号:
FileSeek(iFileHandle,nProductNoAddr,0);
FileWrite(iFileHandle,sProductNo,20);
//处理ID号;
memcpy(sOkCrc+8,sSerialNo,7);
nCrc16Temp=CRC16Check(sOkCrc,15);
FileSeek(iFileHandle,nAddCrc5,0);
memcpy(sBuffer+60,&nCrc16Temp,2);
sBuffer[62]=sBuffer[61];
sBuffer[63]=sBuffer[60];
FileWrite(iFileHandle,sBuffer+62,2);
//在程序的最后写上02 00 00
/*
FileSeek(iFileHandle,4092,0);
sBuffer[62]=2;
FileWrite(iFileHandle,sBuffer+62,1);
*/
//处理全局XOR校验;要入在最后,等全部校验码及所有无效数据全写入后再进行全局校验;
memset(sBuffer,0,sizeof(sBuffer));
FileSeek(iFileHandle,0,0);
FileRead(iFileHandle,sBuffer,4095);
sBuffer[60]=XorCheckSum(sBuffer,4089);
FileSeek(iFileHandle,0xffc,0); //写在4092处
FileWrite(iFileHandle,sBuffer+60,2);
FileClose(iFileHandle);
} |
|