当某个函数的逻辑关系比较复杂时,代码很不好看,所以写了这个脚本来辅助进行人工分析。
下一步会尝试写一个程序来分析这个脚本的输出文件,用来减轻人工分析的工作量。
代码主要作用:
将某个模块的代码以跳转指令作为分界线,将代码分成若干代码段,
然后将代码段的信息输出到文件,并在给每个代码段的开始给代码段
赋予一个Part%d的名称,有利于对代码进行人工分析。 #include <idc.idc>
// Author : HenryShow.
// Version : V0.1
static main()
{
// Declaration of vars
auto CodeStart, CodeEnd, nIndex; // 分析的地址。
auto PartInAddress, PartOutAddress1, PartOutAddress2; // 保存代码段的入口地址,以及出口地址
auto nPartCount; // 保存模块中代码段的个数
auto Instruction, Operand1; // 保存分析出来的命令
auto handle; // 文件句柄
auto TmpString; // 存放类似于Part%d的临时字串。
// 打开文件,用来写入函数中代码段的信息。
handle=fopen("Output.txt","wt");
// 得到当前光标所在的地址作为开始地址
CodeStart=ScreenEA();
// 让用户手动输入结束地址
CodeEnd = AskAddr(0,"Please insert ending address:");
// 如果结束地址比开始地址还小,则结束脚本。
if (CodeEnd <= CodeStart){
fclose(handle);
return;
}
// 代码段个数清零
nPartCount = 0;
nIndex = CodeStart;
// 为代码段的入口地址设置初始值
// 第一段的入口地址就是脚本分析的初地址
PartInAddress = nIndex;
PartOutAddress1 = nIndex;
PartOutAddress2 = nIndex;
// 开始循环判断
while (nIndex < CodeEnd){
if (nIndex == PartInAddress){
// 如果当前地址是某个代码段的入口地址,则在该地址添加Part%d的注释,以便于根据人工分析。
TmpString = "Part" + ltoa(nPartCount+1, 10);
MakeComm(nIndex, TmpString);
}
else{
// 否则将注释清除。
// 如果不需要清除,则将此行注释掉。
MakeComm(nIndex, "");
}
// 得到当前分析地址的指令字符串。
Instruction = GetMnem(nIndex);
if (substr(Instruction, 0, 1) == "j"){
// 如果指令是一个以j开头的指令,则为跳转指令。
// 那么指令的第一个操作数就是出口地址1。
fprintf(handle, "%d ", nPartCount);
fprintf(handle, "%.8X ", PartInAddress);
// 得到操作数对应的地址。
PartOutAddress1 = LocByName(GetOpnd(nIndex, 0));
if (PartOutAddress1 == -1){
// 取不到地址说明为$+*类型的操作数。
Operand1 = GetOpnd(nIndex, 0);
if (substr(Operand1, 0, 1) == "$"){
if (substr(Operand1, 1, 2) == "+"){
// $+*
PartOutAddress1 = nIndex + atol(substr(Operand1, 2, -1));
}
else{
//$-*
PartOutAddress1 = nIndex - atol(substr(Operand1, 2, -1));
}
}
}
fprintf(handle, "%.8X ", PartOutAddress1);
if (substr(Instruction, 0, 3) != "jmp"){
// 如果不是jmp指令,下一条指令的地址就是出口地址2。
fprintf(handle, "%.8X", nIndex + ItemSize(nIndex));
}
else{
// 如果为jmp指令,则只有出口地址1有效。
fprintf(handle, "%.8X", 0);
}
fprintf(handle, "\n");
// 下一个代码段的入口地址就是下一条需要分析的指令的地址。
PartInAddress = nIndex + ItemSize(nIndex);
nPartCount++;
}
else if (Name(nIndex + ItemSize(nIndex)) != ""){
// 如果下一行有一个标号,那么从此地址开始创建下一个代码段。
// 并且将上一个代码段的出口地址1设置为当前地址,而出口地址2为无效地址。
fprintf(handle, "%d ", nPartCount);
fprintf(handle, "%.8X ", PartInAddress);
fprintf(handle, "%.8X ", nIndex + ItemSize(nIndex));
fprintf(handle, "%.8X", 0);
fprintf(handle, "\n");
PartInAddress = nIndex + ItemSize(nIndex);
nPartCount++;
}
// 继续分析下一条指令。
nIndex = nIndex + ItemSize(nIndex);
}
fprintf(handle, "%d ", nPartCount);
fprintf(handle, "%.8X ", PartInAddress);
fprintf(handle, "%.8X ", 0);
fprintf(handle, "%.8X", 0);
fprintf(handle, "\n");
// 关闭文件句柄。
fclose(handle);
return;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!