我在大学有一门课程(逆向工程),我有作业。我有一个 .obj 文件(用 Visual Studio 2008 编译),我必须反汇编它,找出控制结构并在一个小 c 程序中调用它。
我使用了 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 一样在functionfamily 中。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”错误(因此,我猜想我用那个extern关键字声明的.obj文件中没有具有此签名的fb3函数。所以签名错误)。
这是我尝试使用的示例程序(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" 已经在树中了,不是吗?