引言
该出版物旨在研究一些逆向工程技术。 所有材料仅供参考,不得用于任何个人利益。第一部分推荐读物
如果教给外科医生一个人如何工作并给他一把手术刀,那并不意味着他会利用这个知识来损害某人的利益,而且知识渊博的汇编者也没有梦想写出超级病毒。
因此,在这些课程中,您不应该寻找破解和破解的提示。
研究课题
我们将继续研究Visual Studio Atomineer Pro文档(以下称为APD)的插件代码。 让我们熟悉该工具及其功能。
因此,假设我们在C ++中有一个类。
class ClassForReadFile { public: ClassForReadFile(); };
配置APD,以便注释采用Doxygen样式。 我们将光标放在
班级上 ,然后按
CTRL + SHIFT +D。 我们得到以下内容:
class ClassForReadFile { public: ClassForReadFile(); };
该插件添加了一个很好的类描述。 一切都很棒! 我们继续前进。 假设一个类属于一个库,我们必须将其导出。 添加宏并更改类定义
#ifdef DLL_EXPORTS #define DATA_READER_DLL_EXPORTS __declspec(dllexport) #else #define DATA_READER_DLL_EXPORTS __declspec(dllimport) #endif class DATA_READER_DLL_EXPORTS ClassForReadFile { public: ClassForReadFile(); };
对于C ++(Windows OS),情况是标准的。 查看我们的插件。 按
CTRL + SHIFT + D并没有得到我们所期望的
class DATA_READER_DLL_EXPORTS ClassForReadFile { };
DATA_READER_DLL_EXPORTS
定义的名称
被定义为类的名称,而不是
ClassForReadFile ,并且从该名称生成了类描述。 也就是说,在插件代码中,这种情况(即类的导出)未处理或正在处理错误。 这是我们将尝试纠正的问题。
第一步
我们将寻找线索。 首先,由于从C / C ++导出函数和类是一种标准情况,因此我们仍然尝试正确地“强制”插件。 代替DATA_READER_DLL_EXPORTS
定义,插入
__declspec指令
本身并生成文档
class __declspec(dllexport) ClassForReadFile { };
而且,瞧,他们得到了正确的类说明! 因此,我们得出结论,在APD中,有一些代码检查类描述中字符串“ __declspec”的存在,并忽略其进一步的用于构建文档的算法。
我们使用来自Microsoft SDK的标准ildasm.exe反编译该库。 找到“ __declspec”行。 在2种方法CmdDocComment :: a和CmdDocComment :: b中找到它。 第一课 我们将对其进行进一步研究。
第二步
我必须马上说,我们正在寻找的是CmdDocComment ::一个方法
这是
__declspec相遇的地方。 仅显示最有趣的行。
字符串a(CmdDocComment.GeneratorInfo A_0) 我们根据验证后得出的结论
列表[num3] ==“ __declspec”
删除方法被称为
list.RemoveAt(num3);
推理(大声思考):
- CmdDocComment ::方法具有包含字符串数组的局部变量
List<string> list = A_0.e;
- 该数组的第一个元素存储函数,结构,类等的描述的开始,即关键字“类”,“结构”,“联合”
list[0] == "struct"
- 数组的每个元素都包含一个单独的单词。 在我们的情况下,它将是{“ class”,“ DATA_READER_DLL_EXPORTS”,“ ClassForReadFile”}
- 有一个循环遍历数组“ e”的所有元素,查找元素“ __declspec”,然后删除它以及括号中的所有内容
- 退出循环还有其他条件。 这是单词“ where”或“:”的位置。 老实说,不熟悉官方词“ where”,但是在继承类时使用“:”
定义新算法和更改目的:
1.更改不应影响其余功能
2.我们将根据算法删除“列表”数组的元素
-跳过第一个元素;
-如果下一个元素不是“:”而不是“ where”而不是数组的末尾,则删除。
写出所需的周期
仍然需要对其进行编程。
第三步
大声编程。 一般情况下,编程是编写源代码,进行编译,链接。 但是混淆器剥夺了我们这样的机会。 我们将使用推荐的
dnSpy工具 。 我们将直接在库中更改CIL命令的十六进制代码,事实证明,这是非常令人兴奋和有益的! 让我们开始吧。 打开dnSpy,加载库。
选择一会儿,然后将视图更改为IL
我也会列出一个清单,尽管它很庞大
现在,我们在CIL命令中有了一个窗口,它们的十六进制表示形式,文件偏移量和描述。 全部集中在一处。 非常方便(感谢
CrazyAlex25 )。
让我们注意提到“ __declspec”的代码块。 块偏移量0x0001675A。 这将是我们编辑的开始。 接下来,找到RemoveAt方法。 它将对我们保持不变。 该块的最后一个字节是0x000167BF。 转到HEX编辑器
Ctrl + X并在此范围内写入0x00。 我们将保存并检查更改导致的结果。
空循环 while (num3 < list.Count && !(list[num3] == "where") && !(list[num3] == ":")) { if (list[num3] == A_0.b && num2 < 0) { num2 = num3; } list.RemoveAt(num3); num3--; num3++; }
现在,我们将实现新的逻辑。 首先,添加条件
if (num3 != 0 && num3 < list.Count - 1)
下表显示了新命令及其说明。
1119 | ldloc.s | 将具有指定索引的局部变量加载到计算堆栈(缩写形式)上。 |
---|
2C61 | brfalse.s | 如果value为false,空引用或零,则将控制权传递给最终语句。 注意 :如果num3 == 0,则转到增加循环迭代器的步骤。 值0x64是指令0x000167BF的地址偏移量(请参见清单) |
---|
1119 | ldloc.s | 将具有指定索引的局部变量加载到计算堆栈中(简写形式) |
---|
07 | ldloc.1 | 将索引为1的局部变量加载到计算堆栈中 |
---|
6FF700000A | 呼叫病毒 | get_Count()-调用后绑定对象方法并将返回值压入计算堆栈 |
---|
17 | ldc.i4.1 | 将整数值1推入计算堆栈为int32 |
---|
59 | 子 | 从另一个值中减去一个值,并将结果压入计算堆栈。 |
---|
2F55 | 博客 | 如果第一个值大于或等于第二个值,它将控制权转移到最终指令(短格式)。 注意 :如果num3> list.Count-1,则转到增加循环迭代器的步骤。 值0x55是指令0x000167BF之前的地址偏移量 |
---|
我们从偏移量0x0001675A开始写入这些字节。 再次保存并反编译
第一个条件 while (num3 < list.Count && !(list[num3] == "where") && !(list[num3] == ":")) { if (list[num3] == A_0.b && num2 < 0) { num2 = num3; }
现在,我们添加字符串检查“ where”和“:”。 我引用了以下十六进制代码,没有其他注释:
07 11 19 17 58 6F F9 00 00 0A 72 A3 1D 00 70 28 70 00 00 0A 2D 3F 07 11 19 17 58 6F F9 00 00 0A 72 92 5E 00 70 28 70 00 00 0A 2D 29
反编译并获得您的计划
新周期 while (num3 < list.Count && !(list[num3] == "where") && !(list[num3] == ":")) { if (list[num3] == A_0.b && num2 < 0) { num2 = num3; } if (num3 != 0 && num3 < list.Count - 1 && !(list[num3 + 1] == ":") && !(list[num3 + 1] == "where")) { list.RemoveAt(num3); num3--; } num3++; }
通过这些更改,插件将生成以下代码文档:
class DATA_READER_DLL_EXPORTS ClassForReadFile { };
结论
在本课程中,我们学习了如何应用我们的知识来修复错误。 当然,该示例并未反映出错误的全部种类及其处理方式,但这不是“平庸的裂缝”。 我们修复了明显的错误,没有源代码,也没有重建应用程序。