ida是一款常用的静态分析工具,但是需要安装后才能使用,网上可以找到安装后的绿色版或者密钥进行安装,但是没有找到破解版安装包。作为逆向工程初级从业人员,业余分析该工具的密钥算法练练手是不错的选项,对于入门学习者,可以通过复现破解还原过程积累逆向工程经验(萌新第一次发帖,希望各位带佬嘴下留情)。
文章中所有的材料均存放于链接:https://pan.baidu.com/s/16bdMjrWxsP2KfA1MqzE3dQ
提取码:71tr
第一步:
多数安装包都可以通过压缩文件解压,因此首先尝试是否可以解压,选中安装包右键用压缩工具打开发现不能解压,说明该安装包必须在运行时解压内部文件。
第二步:
将安装包拖入到od中进行调试,安装包程序正常运行,猜测可能未进行反调试操作。持续点击下一步直至输入密钥,随机输入密钥单机下一步,弹出密钥错误提示框。在弹窗函数下断点,仍然弹出窗口,如下图所示。
此时保持安装包窗口状态,不要单击确定按钮,回到od,单击k进入堆栈调用窗口,发现程序并没有调用弹窗函数,且也没有调用窗口创建函数,猜测该安装程序并非单一进程。
第三步:
未验证安装程序为多进程的猜想,使用od重新载入该安装程序,在creatfile函数处下断点,监控到进程往系统的临时文件夹创建了一个文件,如下图所示。
为证明该文件即为安装子进程,给创建进程的函数下一个断点,如下图所示。
od按下F8运行,此时出现安装程序。表明:主进程在系统临时文件夹创建一个临时安装进程,并将自身地址作为命令行参数启动,安装进程进行密钥检测并解压主进程进行安装。
第四步:
在了解程序的框架之后对安装程序进程密钥相关算法进行逆向还原,ida打开该文件,如下图所示。
入口函数接口较为复杂,无法直接定位到算法函数,因此先使用od附加调试(调试时进入线程窗口激活所有线程)定位至算法函数再进行代码还原,如下图进行附加调试。
选中对应的进程
程序在弹窗函数断点
栈回溯找到调用源
并在函数478FFC处发现疑似密钥计算函数(此处在条件跳转指令进行比较的内存处下内存写入断点可以定位,这里就不演示了),如下图所示。
第五步:
对密钥校验算法进行还原,使用ida打开安装子进程文件,F5反编译,如下图所示:
原始idb文件
根据自己的理解和动态调试结果修改的idb文件
第六步:
还原idb文件为源代码,如下:
#include<stdio.h>
#include<Windows.h>
int GetSeedEnd(unsigned int a1)
{
return (a1 >> 24) | ((a1 & 0xFF0000) >> 8) | ((unsigned __int16)(a1 & 0xFF00) << 8) | (a1 << 24);
}
int GetSeedFirst(unsigned char * a1, int a2, int a3)
{
unsigned char * Local1 = a1;
/*此处位运算无法根据idb还原*/
a3 = a3 & 0xFFFF00FF;
a3 |= ((a3 & 0xFF) << 8);
/**/
unsigned int Local3 = a3 << 16;
/*此处位运算无法根据idb还原*/
Local3 = Local3 & 0xFFFF0000;
Local3 |= a3 & 0xFFFF;
/**/
int Local2 = a2 >> 2;
if (a2 >> 2 >= 0)
{
memset(Local1, Local3, Local2);
memset(&Local1[4 * Local2], Local3, a2 & 3);
}
return Local3;
}
unsigned int * CalculateSeedEnd(unsigned int * a1, unsigned int * a2, unsigned int * a3)
{
unsigned int * Local1 = a1;
unsigned int * Local2 = a2;
unsigned int * Local3 = a3;
unsigned int LocalFlag1[5] = { 0 };
unsigned int * LocalFlag3 = Local3;
unsigned int * LocalFlag4 = Local3 + 13;
unsigned int * LocalFlag5 = Local3;
int LocalFlag6;
unsigned int * LocalFlag7 = Local3 + 20;
unsigned int * LocalFlag8 = Local3 + 40;
int LocalFlag9;
int LocalFlag10;
unsigned int * LocalFlag11 = Local3 + 40;
int LocalFlag12;
unsigned int * result;
int count = 16;
do
{
*LocalFlag3 = (*Local2 >> 24) | ((*Local2 & 0xFF0000u) >> 8) | ((*Local2 & 0xFF00) << 8) | (*Local2 << 24);
++LocalFlag3;
++Local2;
--count;
} while (count);
count = 64;
do
{
LocalFlag4[3] = ((*(LocalFlag4 - 13) ^ *(LocalFlag4 - 11) ^ (unsigned int)(*(LocalFlag4 - 5) ^ *LocalFlag4)) >> 31) | 2 * (*(LocalFlag4 - 13) ^ *(LocalFlag4 - 11) ^ *(LocalFlag4 - 5) ^ *LocalFlag4);
++LocalFlag4;
--count;
} while (count);
LocalFlag1[0] = *Local1;
LocalFlag1[1] = Local1[1];
LocalFlag1[2] = Local1[2];
LocalFlag1[3] = Local1[3];
LocalFlag1[4] = Local1[4];
count = 20;
do
{
LocalFlag6 = *LocalFlag5
+ LocalFlag1[4]
+ (LocalFlag1[3] ^ LocalFlag1[1] & (LocalFlag1[3] ^ LocalFlag1[2]))
+ ((LocalFlag1[0] >> 27) | 32 * LocalFlag1[0])
+ 1518500249;
LocalFlag1[4] = LocalFlag1[3];
LocalFlag1[3] = LocalFlag1[2];
LocalFlag1[2] = (LocalFlag1[1] >> 2) | (LocalFlag1[1] << 30);
LocalFlag1[1] = LocalFlag1[0];
LocalFlag1[0] = LocalFlag6;
++LocalFlag5;
--count;
} while (count);
count = 20;
LocalFlag7 = Local3 + 20;
do
{
LocalFlag9 = *LocalFlag7
+ LocalFlag1[4]
+ (LocalFlag1[3] ^ LocalFlag1[1] ^ LocalFlag1[2])
+ ((LocalFlag1[0] >> 27) | 32 * LocalFlag1[0])
+ 1859775393;
LocalFlag1[4] = LocalFlag1[3];
LocalFlag1[3] = LocalFlag1[2];
LocalFlag1[2] = (LocalFlag1[1] >> 2) | (LocalFlag1[1] << 30);
LocalFlag1[1] = LocalFlag1[0];
LocalFlag1[0] = LocalFlag9;
++LocalFlag7;
--count;
} while (count);
count = 20;
LocalFlag8 = Local3 + 40;
do
{
LocalFlag10 = *LocalFlag8
+ LocalFlag1[4]
+ (LocalFlag1[3] & LocalFlag1[2] | LocalFlag1[1] & LocalFlag1[3] | LocalFlag1[1] & LocalFlag1[2])
+ ((LocalFlag1[0] >> 27) | 32 * LocalFlag1[0])
- 1894007588;
LocalFlag1[4] = LocalFlag1[3];
LocalFlag1[3] = LocalFlag1[2];
LocalFlag1[2] = (LocalFlag1[1] >> 2) | (LocalFlag1[1] << 30);
LocalFlag1[1] = LocalFlag1[0];
LocalFlag1[0] = LocalFlag10;
++LocalFlag8;
--count;
} while (count);
count = 20;
LocalFlag11 = Local3 + 60;
do
{
LocalFlag12 = *LocalFlag11
+ LocalFlag1[4]
+ (LocalFlag1[3] ^ LocalFlag1[1] ^ LocalFlag1[2])
+ ((LocalFlag1[0] >> 27) | 32 * LocalFlag1[0])
- 899497514;
LocalFlag1[4] = LocalFlag1[3];
LocalFlag1[3] = LocalFlag1[2];
LocalFlag1[2] = (LocalFlag1[1] >> 2) | (LocalFlag1[1] << 30);
LocalFlag1[1] = LocalFlag1[0];
LocalFlag1[0] = LocalFlag12;
++LocalFlag11;
--count;
} while (count);
*Local1 += LocalFlag12;
Local1[1] += LocalFlag1[1];
Local1[2] += LocalF
lag1[2];
Local1[3] += LocalFlag1[3];
result = Local1;
result[4] += LocalFlag1[4];
return result;
}
int CalculateSeedFirst(unsigned char * Seed, unsigned char * InitSeed, unsigned int Length)
{
unsigned char * LocalFlag1 = Seed;
unsigned char * LocalFlag2;
unsigned char * LocalFlag3;
int LocalFlag4;
int LocalFlag5;
BYTE * LocalFlag6;
BYTE * LocalFlag7;
int result = Length;
/*此处指针比较代码存在漏洞,在建议直接走else分支/
if ((signed int)InitSeed > (signed int)LocalFlag1)
{
LocalFlag2 = &LocalFlag1[Length - 4];
LocalFlag3 = &InitSeed[Length - 4];
LocalFlag4 = Length >> 2;
if (LocalFlag4 >= 0)
{
while (LocalFlag4)
{
*(DWORD *)LocalFlag3 = *(DWORD *)LocalFlag2;
LocalFlag2 -= 4;
LocalFlag3 -= 4;
--LocalFlag4;
}
LocalFlag5 = result & 3;
LocalFlag6 = LocalFlag2 + 3;
LocalFlag7 = LocalFlag3 + 3;
while (LocalFlag5)
{
*LocalFlag7-- = *LocalFlag6--;
--LocalFlag5;
}
}
}else if (InitSeed != LocalFlag1)
{
int p = Length >> 2;
if (p >= 0)
memcpy(InitSeed, LocalFlag1, 4 * p + (result & 3));
}
return result;
}
int GetHashCode(unsigned int * HashCode, unsigned char * MyHashCode)
{
unsigned int * LocalHashCode = HashCode;
unsigned char * LocalMyHashCode = MyHashCode;
unsigned int LocalFlag1 = HashCode[5] & 0x3F;
BYTE * LocalFlag2 = (unsigned char *)LocalHashCode + LocalFlag1 + 28;
*LocalFlag2 = 0x80;
unsigned char * LocalFlag3 = LocalFlag2 + 1;
int LocalFlag4 = 55 - LocalFlag1;
int LocalFlag5 = 5;
unsigned int * LocalFlag6 = LocalHashCode;
if (LocalFlag4 < 0)
{
GetSeedFirst(LocalFlag3, LocalFlag4 + 8, 0);
CalculateSeedEnd(LocalHashCode, LocalHashCode + 7, LocalHashCode + 23);
LocalFlag3 = (unsigned char *)(LocalHashCode + 7);
LocalFlag4 = 56;
}
GetSeedFirst(LocalFlag3, LocalFlag4, 0);
LocalHashCode[22] = GetSeedEnd(8 * LocalHashCode[5]);
LocalHashCode[21] = GetSeedEnd(LocalHashCode[5] >> 29);////check
CalculateSeedEnd(LocalHashCode, LocalHashCode + 7, LocalHashCode + 23);
do
{
*LocalFlag6 = GetSeedEnd(*LocalFlag6);
++LocalFlag6;
--LocalFlag5;
} while (LocalFlag5);
CalculateSeedFirst((unsigned char *)LocalHashCode, LocalMyHashCode, 20);
return GetSeedFirst((unsigned char *)LocalHashCode, 412, 0);
}
int CalculateHashCode(unsigned int * HashCode, unsigned char * Seed, unsigned int SeedLength)
{
unsigned int LocalSeedLength = SeedLength;
unsigned int * LocalHashCode = HashCode;
unsigned char * LocalSeed = Seed;
unsigned int LocalFlag1 = HashCode[5];
unsigned int LocalFlag2;
unsigned char * LocalSeedforCalculate;
unsigned int i;
LocalHashCode[5] += LocalSeedLength;
if (HashCode[5] < LocalFlag1)
++HashCode[6];
LocalFlag2 = 64 - (LocalFlag1 & 0x3F);
if (LocalFlag2 > SeedLength)
return CalculateSeedFirst(Seed, (unsigned char *)HashCode - LocalFlag2 + 92, SeedLength);
CalculateSeedFirst(Seed, (unsigned char *)HashCode - LocalFlag2 + 92, LocalFlag2);
CalculateSeedEnd(LocalHashCode, LocalHashCode + 7, LocalHashCode + 23);
LocalSeedforCalculate = &LocalSeed[LocalFlag2];
for (i = LocalSeedLength - LocalFlag2; i >= 0x40; i -= 64)
{
CalculateSeedFirst(LocalSeedforCalculate, (unsigned char *)LocalHashCode + 28, 64);
CalculateSeedEnd(LocalHashCode, LocalHashCode + 7, LocalHashCode + 23);
LocalSeedforCalculate += 64;
}
return CalculateSeedFirst(LocalSeedforCalculate, (unsigned char *)LocalHashCode + 28, i);
}
void * InitHashCode(unsigned int * InitHashCode)
{
InitHashCode[0] = 0x67452301;
InitHashCode[1] = 0xEFCDAB89;
InitHashCode[2] = 0x98BADCFE;
InitHashCode[3] = 0x10325476;
InitHashCode[4] = 0xC3D2E1F0;
InitHashCode[5] = 0;
InitHashCode[6] = 0;
return InitHashCode;
}
int GetValidPassword(unsigned char * Password)
{
unsigned char * LocalPassword = Password;
unsigned char * LocalSeed1 = (unsigned char *)"PasswordCheckHash";
unsigned char LocalSeed2[8] = { 0x58 ,0x72 ,0x44 ,0xF1 ,0xB0 ,0x7B ,0x1B ,0x32};
unsigned int LengthOfPassword = strlen((const char *)LocalPassword);
unsigned int LocalInitHashCode[28] = { 0 };
unsigned char MyHashCode[32] = { 0 };
if (LengthOfPassword == 0)return 0;
InitHashCode(LocalInitHashCode);
CalculateHashCode(LocalInitHashCode, LocalSeed1, 0x11);
CalculateHashCode(LocalInitHashCode, LocalSeed2, 0x8);
CalculateHashCode(LocalInitHashCode, LocalPassword, LengthOfPassword);
unsigned int * p = (unsigned int *)malloc(1024 * 4);
memcpy(p, LocalInitHashCode, 28 * 4);
GetHashCode(p, MyHashCode);//LocalInitHashCode作为具部变量容易堆栈崩溃
free(p);
return 1;
}
int main()
{
char * Password = "123456";
GetValidPassword((unsigned char *)Password);//合法的hashcode为73 4D 89 77 37 77 82 3E 11 C1 E6 25 51 B3 D3 51 00 CF 9C C7
return 0;
}
编译并于源程序比对测试,如下图所示:
还原代码计算的hashcode
安装子进程计算的hashcode
通过代码计算的hashcode与源程序计算的hashcode相同,算法还原成功(待完全待验证,欢迎补充)。合法hashcode为“73 4D 89 77 37 77 82 3E 11 C1 E6 25 51 B3 D3 51 00 CF 9C C7”,可通过计算碰撞还原合法密钥(欢迎尝试)。
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界