感受风格:
一个程序是否优秀风格很重要,在看过大智慧的代码后,优秀这是我最先想到的赞美,虽然我已经基本不用大智慧来看股票,在来到论坛后被通达信界面的简洁明朗的风格吸引,基本上放弃了大智慧的使用,看代码并不影响看股票软件的选择~~:)
对于相对于通达信的内存泄漏,大智慧这方面无疑要优秀的多;
在读他的代码中的异常抛出,new 后必定有 delete,极少的全局变量,都说明是也非常规范的程序设计;
好了废话不说了,现在我们开始展开算法的跟踪和阅读;
在开始我们就用了sub_54F555来说这是按修改按钮后进入的代码点,其实在这之前还有先于它执行的,但对算法本身来说我们选择了省略,看来这是一错误的决定,因为我们现在必须要知道:(,好吧它之前被执行的顺序是:
sub_5516F5 sub_6DA0E5 sub_50B8AD sub_54F555
int __cdecl sub_54F555(int a1, void *a2, int a3);这个函数传递进来的参数是什么,在反相调试中很多时候参数的数据类型我们不必太讲究,本身C语言很多时候的数据类型是可以换转的,对于这种现象不再刻意说明,只要明白他们的原理即可;
那么此时利用IDA的图很容易找到他的上一层sub_50B8AD,如图所示:
.text:0050B90D push edi ; Buf1
.text:0050B90E call sub_548EC9
.text:0050B913 mov ebx, eax
.text:0050B915 pop ecx
.text:0050B916 test ebx, ebx
.text:0050B918 jz loc_50BA9E
.text:0050B91E test dword ptr [ebx+4], 1000h
.text:0050B925 jnz loc_50BA9E
.text:0050B92B cmp dword_A512D8, 5
.text:0050B932 jge short loc_50B943
.text:0050B934 mov ecx, ebx
.text:0050B936 call sub_549941
.text:0050B93B test eax, eax
.text:0050B93D jnz loc_50BA9E
.text:0050B943
.text:0050B943 loc_50B943: ; CODE XREF: sub_50B8AD+85j
.text:0050B943 and dword ptr [esi+0E0h], 0
.text:0050B94A push ebx
.text:0050B94B lea ecx, [esi+0E4h]
.text:0050B951 call sub_54D1EA
.text:0050B956 lea eax, [esi+1ABh]
.text:0050B95C push eax ; a3
.text:0050B95D lea eax, [esi+1AFh]
.text:0050B963 push eax ; a2
.text:0050B964 push ebx ; a1
.text:0050B965 call sub_54F555 ; 公式管理器"算法"验证
.text:0050B96A add esp, 0Ch
.text:0050B96D test eax, eax
.text:0050B96F jz loc_50BA9E
在这段代码中call sub_54F555 前有三个push 按照从右到左的参数入栈规则 前两个是公式列表框的数据(this)数据从控件中获取,最后一个是下面代码中作为KEY来用的a1,那么a1从什么地方来是什么?看下下面的代码
int __cdecl sub_548EC9(char *Buf1)
{
char *v1; // esi@1
v1 = Buf1;
if ( memcmp(Buf1, "IND-", 4u) )
{
if ( memcmp(Buf1, "EXP-", 4u) )
{
if ( memcmp(Buf1, "SYS-", 4u) )
{
if ( !memcmp(Buf1, "CLR-", 4u) )
v1 = Buf1 + 4;
}
else
{
v1 = Buf1 + 4;
}
}
else
{
v1 = Buf1 + 4;
}
}
else
{
v1 = Buf1 + 4;
}
return sub_5484EE(v1);
}
int __stdcall sub_5484EE(int a1)
{
int v2; // eax@1
v2 = CMapStringToOb__Lookup(a1, &a1);
return v2 != 0 ? a1 : 0;
}
哦,原来是用CMapStringToOb::Lookup 查找到的含下列关键字的映射 IND- EXP- SYS- !CLR- 并将返回的值
嗯,第一个关键点找到来源了,先暂时标记下,然后看看其他地方吧
前文说到int __cdecl sub_54F555(int a1, void *a2, int a3)中的参数A1很重要;
在通过CMapStringToOb::Lookup找到了A1目标地址后接下来我们看看他们又干了些什么,口令起到了什么作用
先上个图刺激下老师同学们,省得说KEY不知道在哪里~:)
如图在通过CMapStringToOb::Lookup找到了目标的地址是06322978(这个地址只对这次有效就不用特意知道为什么了),反正大智慧已经告诉我们是可以用CMapStringToOb::Lookup找到目标的,今后有大师想搞个遍历的公式XX的,不用想按照大智慧的法子去就行了;
在图中我们知道了063222978是我们反相出的A1参数,也指出过关键点是:
if ( sub_54952D(v12) == *(_DWORD *)(*(_DWORD *)(a1 + 155) + 4) )
break;
v13 = (const char *)ATL__CSimpleStringT_char_1___operator char_const__(&v20);
if ( sub_549574(v13) == *(_DWORD *)(*(_DWORD *)(a1 + 155) + 4) )
break;
A1 = 06322978h
那么
A1+ 155 = 06322A13h(A1+9Bh = 06322A13h)
他的内容是 78 2A 32 06 也就是 06322A78h
地址06322A78h + 4h 指向的地址内容是 F4 1C 46 06
比较的关键值是 EAX == 06322A78 + 4 指向的值
如果相同表示密码正确 ~~:) 哈是不是很简单?
在密码学中,如果有明文是,并且明文是可逆的那么设明文为 A 设加密后的密文为 M
加密的函数 M= D(A)
解密的函数 W= S(M)
必然 A=S(M)=S(D(A))
A=S(D(A))
int __cdecl sub_4611CA(int a1, int a2, int a3, signed int a4, int a5) 为什么被多次调用,验证密码和解码的时候它在做什么?
补充内容:
1,搞一个最简单的公式,并且只有一个公式
2,加密码,以后每次都用相同密码
3,保存文件,备份他,再比较他看每次加密和不加密,以及不同时间加密之间有什么变化,注意用相同内容和相同密码,看他们的变化;如果有足够的能力也可以直接阅读代码;
4,看进入int __cdecl sub_54F555(int a1, void *a2, int a3)前A1指向的那片区域内容,不同的有密码和无密码做比较,多次比较;
5,观察在比较密码阶段int __cdecl sub_4611CA(int a1, int a2, int a3, signed int a4, int a5)和密码正确阶段,传递的值和返回的值
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)