我在大学有一门课程(逆向工程),我有一份功课。 我有一个.obj文件(使用visual studio 2008编译),我必须反汇编它,找出控制结构并在一个小程序中调用它。
我使用了IDA反编译器,这里是asm代码:
_FB3:
00000000: 55 push ebp
00000001: 56 push esi
00000002: 57 push edi
00000003: 8B 7C 24 10 mov edi,dword ptr [esp+10h]
00000007: 83 3F 00 cmp dword ptr [edi],0
0000000A: 74 79 je 00000085
0000000C: 8D 64 24 00 lea esp,[esp]
00000010: 8B 2F mov ebp,dword ptr [edi]
00000012: 8B 75 00 mov esi,dword ptr [ebp]
00000015: 8B 44 24 14 mov eax,dword ptr [esp+14h]
00000019: 8B CE mov ecx,esi
0000001B: EB 03 jmp 00000020
0000001D: 8D 49 00 lea ecx,[ecx]
00000020: 8A 10 mov dl,byte ptr [eax]
00000022: 3A 11 cmp dl,byte ptr [ecx]
00000024: 75 1A jne 00000040
00000026: 84 D2 test dl,dl
00000028: 74 12 je 0000003C
0000002A: 8A 50 01 mov dl,byte ptr [eax+1]
0000002D: 3A 51 01 cmp dl,byte ptr [ecx+1]
00000030: 75 0E jne 00000040
00000032: 83 C0 02 add eax,2
00000035: 83 C1 02 add ecx,2
00000038: 84 D2 test dl,dl
0000003A: 75 E4 jne 00000020
0000003C: 33 C0 xor eax,eax
0000003E: EB 05 jmp 00000045
00000040: 1B C0 sbb eax,eax
00000042: 83 D8 FF sbb eax,0FFFFFFFFh
00000045: 85 C0 test eax,eax
00000047: 7D 05 jge 0000004E
00000049: 8D 7D 0C lea edi,[ebp+0Ch]
0000004C: EB 32 jmp 00000080
0000004E: 8B 44 24 14 mov eax,dword ptr [esp+14h]
00000052: 8B CE mov ecx,esi
00000054: 8A 10 mov dl,byte ptr [eax]
00000056: 3A 11 cmp dl,byte ptr [ecx]
00000058: 75 1A jne 00000074
0000005A: 84 D2 test dl,dl
0000005C: 74 12 je 00000070
0000005E: 8A 50 01 mov dl,byte ptr [eax+1]
00000061: 3A 51 01 cmp dl,byte ptr [ecx+1]
00000064: 75 0E jne 00000074
00000066: 83 C0 02 add eax,2
00000069: 83 C1 02 add ecx,2
0000006C: 84 D2 test dl,dl
0000006E: 75 E4 jne 00000054
00000070: 33 C0 xor eax,eax
00000072: EB 05 jmp 00000079
00000074: 1B C0 sbb eax,eax
00000076: 83 D8 FF sbb eax,0FFFFFFFFh
00000079: 85 C0 test eax,eax
0000007B: 7E 1E jle 0000009B
0000007D: 8D 7D 08 lea edi,[ebp+8]
00000080: 83 3F 00 cmp dword ptr [edi],0
00000083: 75 8B jne 00000010
00000085: 6A 10 push 10h
00000087: E8 00 00 00 00 call _malloc
0000008C: 83 C4 04 add esp,4
0000008F: 89 07 mov dword ptr [edi],eax
00000091: 85 C0 test eax,eax
00000093: 75 14 jne 000000A9
00000095: 5F pop edi
00000096: 5E pop esi
00000097: 33 C0 xor eax,eax
00000099: 5D pop ebp
0000009A: C3 ret
0000009B: 8B C5 mov eax,ebp
0000009D: FF 40 04 inc dword ptr [eax+4]
000000A0: 5F pop edi
000000A1: 5E pop esi
000000A2: B8 01 00 00 00 mov eax,1
000000A7: 5D pop ebp
000000A8: C3 ret
000000A9: 8B 74 24 14 mov esi,dword ptr [esp+14h]
000000AD: 8B C6 mov eax,esi
000000AF: 8D 50 01 lea edx,[eax+1]
000000B2: 8A 08 mov cl,byte ptr [eax]
000000B4: 40 inc eax
000000B5: 84 C9 test cl,cl
000000B7: 75 F9 jne 000000B2
000000B9: 2B C2 sub eax,edx
000000BB: 40 inc eax
000000BC: 50 push eax
000000BD: E8 00 00 00 00 call _malloc
000000C2: 8B 0F mov ecx,dword ptr [edi]
000000C4: 89 01 mov dword ptr [ecx],eax
000000C6: 8B 07 mov eax,dword ptr [edi]
000000C8: 83 C4 04 add esp,4
000000CB: 83 38 00 cmp dword ptr [eax],0
000000CE: 74 C5 je 00000095
000000D0: 8B 10 mov edx,dword ptr [eax]
000000D2: 8B CE mov ecx,esi
000000D4: 8A 01 mov al,byte ptr [ecx]
000000D6: 88 02 mov byte ptr [edx],al
000000D8: 41 inc ecx
000000D9: 42 inc edx
000000DA: 84 C0 test al,al
000000DC: 75 F6 jne 000000D4
000000DE: 8B 17 mov edx,dword ptr [edi]
000000E0: C7 42 04 01 00 00 mov dword ptr [edx+4],1
00
000000E7: 8B 07 mov eax,dword ptr [edi]
000000E9: C7 40 08 00 00 00 mov dword ptr [eax+8],0
00
000000F0: 8B 0F mov ecx,dword ptr [edi]
000000F2: 5F pop edi
000000F3: 5E pop esi
000000F4: C7 41 0C 00 00 00 mov dword ptr [ecx+0Ch],0
00
000000FB: B8 01 00 00 00 mov eax,1
00000100: 5D pop ebp
00000101: C3 ret
IDA让我成为一个不错的控制结构:
正如您所看到的,代码是这样的:
for(...)
{
for1(...){...}
...
for1(...){...}
}
malloc
....
for3() ...
malloc
...
for2(...)
{
...
}
我知道for1和for2具有几乎相同的结构,只有活动是不同的,for3的实现函数在函数家族中为for1和for2。 for3使用第二个malloc的结果作为参数,所以我认为for2应该是某种数组复制循环。 for1,for2和for3是已知的stdc内联实现。
有人可以帮助我弄清楚这个f3功能的用途吗?
第二个问题:如何在一个小样本C程序中使用这个.obj文件? 我怎样才能在VS中调用它的功能?
在此先感谢,感谢任何帮助。
更新: 杰斯特:很有意思。你是怎么知道节点的结构的? 我还在试图找出这一切(在你的帮助下),但还没有。
我发现,IDA反汇编程序具有伪代码查看功能。 这是伪:
signed int __cdecl FB3(int a1, const char *a2)
{
int v2; // edi@1
const char **v3; // ebp@2
void *v4; // eax@7
signed int result; // eax@8
int v6; // edx@11
const char *v7; // ecx@11
const char v8; // al@12
v2 = a1;
while ( *(_DWORD *)v2 )
{
v3 = *(const char ***)v2;
if ( strcmp(a2, **(const char ***)v2) >= 0 )
{
if ( strcmp(a2, **(const char ***)v2) <= 0 )
{
++v3[1];
return 1;
}
v2 = (int)(v3 + 2);
}
else
{
v2 = (int)(v3 + 3);
}
}
v4 = malloc(0x10u);
*(_DWORD *)v2 = v4;
if ( v4 && (**(_DWORD **)v2 = malloc(strlen(a2) + 1)) != 0 )
{
v6 = **(_DWORD **)v2;
v7 = a2;
do
{
v8 = *v7;
*(_BYTE *)v6++ = *v7++;
}
while ( v8 );
*(_DWORD *)(*(_DWORD *)v2 + 4) = 1;
*(_DWORD *)(*(_DWORD *)v2 + 8) = 0;
*(_DWORD *)(*(_DWORD *)v2 + 12) = 0;
result = 1;
}
else
{
result = 0;
}
return result;
}
从这可能它会计算一个数字出现在一个字符串中? 这个伪代码对我来说有点迷雾。
我试图在示例程序中调用此函数,但没有成功。 我用过:extern signed int fb3(int a1,const char * a2); 然后我试着调用它,但是链接器给了我“在函数_main中引用的未解析的外部符号_fb3”错误(所以,在.obj文件中没有这个签名的fb3函数,我用那个extern关键字声明我猜。所以签名错了。)
以下是我尝试使用的示例程序(main.c):
#include <stdio.h>
extern signed int fb3(int a1, const char *a2);
int main(void)
{
char b[3] = {'e','3','y'};
signed int i = fb3(3,b);
printf("%d",i);
return 0;
}
我已经将链接器输入(vs2010)设置为f3.obj。
UPDATE2: 我实现了节点结构,并使用区分大小写的函数名称,现在我可以成功编译。
示例程序:
#include <stdio.h>
typedef struct node
{
int count;
const char * text;
struct node* right;
struct node* left;
} node;
extern int FB3(node* root, const char *text);
int main(void)
{
node* root;
signed int i;
int j;
root = (node*)malloc(sizeof(node));
root->count = 0;
root->text = "textone";
root->right = NULL;
root->left = NULL;
printf("value = %d\n", FB3(root,"v"));
printf("value = %d\n", FB3(root,"b"));
printf("value = %d\n", FB3(root,"c"));
printf("value = %d\n", FB3(root,"3dasf"));
printf("value = %d\n", FB3(root,"3ssdfs"));
printf("value = %d\n", FB3(root,"dsda"));
printf("value = %d\n", FB3(root,"v"));
printf("value = %d\n", FB3(root,"gsda"));
printf("value = %d\n", FB3(root,"gsda"));
printf("value = %d\n", FB3(root,"a"));
printf("value = %d\n", FB3(root,"ab"));
return 0;
}
输出结果为:
value=1
value=1
value=1
... (only value=1)
有趣的是,第7个printf应该printf“value = 2”,因为“v”已经在树中了,不是吗?
答案 0 :(得分:2)
从快速浏览一下,这似乎是一个用于计算字符串出现次数的二叉树。树节点看起来像:
const char* text;
int count;
node* left;
node* right;
函数本身是int addstring(node** root, const char* text)
首先,代码检查树是否为空,如果是,则跳过搜索。
搜索从0x10开始,执行if (strcmp(current->text, text) > 0) current = current->right;
并循环返回。此代码看起来没有优化,在0x4E它进行相同的比较,这次检查< 0
并向左移动。在0x9B处是“找到”分支,它递增计数器并返回1.
如果找不到文本,则在0x85创建一个新节点,插入到树中,然后使用strdup
将文本复制到其中(实现为malloc(strlen())
+ strcpy
)。新节点的left
和right
都设置为NULL
,count
设置为1。
更新:从malloc
调用可以看出,节点大小为16字节。偏移0用于比较文本,因此必须是文本。偏移4递增,因此必须是计数器。偏移量8和12是两个子指针,因为它们是这样使用的。
原型IDA提出的是废话,第一个参数必须是一个指针,否则会爆炸。此外,C区分大小写,因此请尝试FB3
(大写字母)。
像这样:
#include <stdio.h>
extern int FB3(void** root, const char *text);
int main(void)
{
void* root = NULL;
int i = FB3(&root, "e3y");
printf("%p %d", root, i);
return 0;
}
如果可行,您可以继续添加节点结构,然后可以从C遍历并打印树。