这是半夜,我通过输入
意外地覆盖了我的所有工作gcc source.c -o source.c
我仍然拥有原始的二进制文件,我唯一的希望就是解读它,但我不知道如何或最好的工具来获得最可读的结果。我知道这可能不是发布的正确位置,但我很强调。有人可以帮帮我吗?
答案 0 :(得分:4)
有几种工具(您可以使用Google进行搜索),但我建议您重新编码。您将投资重构反汇编程序将重新编码的时间可能高于重新编码。
我知道这似乎很明显,但正确的答案是:从备份恢复(你应该拥有)
答案 1 :(得分:4)
感谢您上传文件。我怀疑它是未被剥离的,所以功能名称仍然存在。除了标准的样板代码,我还可以识别函数main
,register_broker
,connect_exchange
(未使用和空)和handle_requests
。
我在IDA Pro上花了一些时间,恢复main()
功能并不太难。首先,这是来自IDA的main()
的原始未经修改的列表:http://pastebin.com/sBxhRJMM
要继续,您需要熟悉AMD64 calling convention。总而言之,前四个参数在RDI(EDI),RSI(ESI),RDX(EDX)和RCX(ECX)中传递。其余的都在堆栈上传递,但main()
中的所有调用只使用最多四个参数,所以我们不需要担心。
IDA帮助标记了标准C函数的参数,甚至重命名了一些局部变量。但是,它可以进一步改进和评论。例如,由于我们在main()
,我们知道argc
(第一个参数)来自EDI(因为它是int
意味着32位,它只使用低半部分RDI)和argv
来自RSI(它是一个指针,因此它使用寄存器的完整8个字节)。因此,我们可以重命名复制EDI和RSI的局部变量:
mov [rbp+argc], edi
mov [rbp+argv], rsi
接下来是一个简单的条件块:
cmp [rbp+argc], 2
jz short loc_400EB3
mov rax, cs:stderr@@GLIBC_2_2_5
mov rdx, rax
mov eax, offset aUsage ; "Usage"
mov rcx, rdx ; s
mov edx, 5 ; n
mov esi, 1 ; size
mov rdi, rax ; ptr
call _fwrite
mov edi, 1 ; status
call _exit
这里我们将argc与2进行比较,如果它相等,我们会在代码中进一步跳转。如果不相等,我们会调用fwrite()
。它的第一个参数是rdi
,rdi
是从rax
加载的,esi
包含一个常量字符串“Usage”的地址。第二个参数位于edx
并且为1,是rcx
中的第三个参数,并且是rdx
中的第四个参数,它是从stderr@@GLIBC_2_2_5
加载的,其值为{ {1}},它基本上是对来自libc的stderr
变量的奇特引用。将它们串起来,我们得到:
fwrite("Usage", 1, 5, stderr);
根据我的经验,我可以说很可能是内联fprintf
,因为5正好是字符串的长度。即原始代码可能是:
fprintf(stderr, "Usage");
下一个电话是一个简单的exit(1);
。结合两者进行比较,我们得到:
if ( argc != 2 )
{
fprintf(stderr, "Usage");
exit(1);
}
继续这样,我们可以识别他们使用的其他调用和变量。描述这一切有点单调乏味,所以我上传了反汇编的评论版本,在那里我尝试显示每个调用的等效C代码。你可以在这里看到它:http://pastebin.com/p5sRSwgQ
从评论的版本来看,想象main()
的可能版本并不是很难:
int main(int argc, char **argv)
{
if ( argc != 2 )
{
fprintf(stderr, "Usage");
exit(1);
}
char name[256];
gethostname(name, sizeof(name));
struct hostent* _hostent = gethostbyname(name);
struct in_addr *_addr0 = (struct in_addr *)(_hostent->h_addr_list[0]);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(0);
addr.sin_addr.s_addr = _addr0->s_addr;
char *tmp = (char *)malloc(6);
sprintf(tmp, "%d", addr.sin_port);
char *ip_str = inet_ntoa(*_addr0);
char *newbuf = (char *)malloc(strlen(argv[1]) + strlen(ip_str) + strlen(tmp) + 5);
strcpy(newbuf, "r");
strcat(newbuf, " ");
strcat(newbuf, argv[1]);
strcat(newbuf, " ");
strcat(newbuf, ip_str);
strcat(newbuf, " ");
strcat(newbuf, tmp);
register_broker(newbuf);
int fd = socket(PF_INET, SOCK_STREAM, 0);
if ( fd < 0 )
{
perror("Error creating socket");
exit(1);
}
if ( bind(fd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("Error binding socket");
exit(1);
}
if ( listen(fd, 0x80) != 0 )
{
perror("Error listening on socket");
exit(1);
}
handle_requests(fd);
}
恢复其他两个功能是为读者留下的练习:)
答案 2 :(得分:3)
遗憾的是,从二进制文件回到源代码确实没有好办法。你可以尝试Boomerang,但我真的不希望得到好的结果。
答案 3 :(得分:2)
首先,查找备份源文件。大多数编辑器会为每个文件保存创建名为.bak
或filename.c~
的文件。在Windows计算机上,取证软件工具可能能够检索最后的源文件。我写的工具getfile
曾经由NTI提供,但几年前被Armor Holdings收购 - 不知道它是否仍然可用。
如果代码是可运行的,通常在strace()
实用程序(Linux发行版的标准组件)下运行它可以帮助解码程序的某些方面,特别是如果它是面向i / o的。唉,如果该程序主要是内部数据操作,那么这没什么用处。 Strace()
创建程序传递的系统调用和参数的日志;它有时是理解程序行为的宝贵工具。例如,strace date
生成(部分 - 我省略了运行时库启动):
clock_gettime(CLOCK_REALTIME, {1315760058, 681379835}) = 0
open("/etc/localtime", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=2819, ...}) = 0
fstat64(3, {st_mode=S_IFREG|0644, st_size=2819, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78b5000
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\4\0\0\0\0"..., 4096) = 2819
_llseek(3, -24, [2795], SEEK_CUR) = 0
read(3, "\nPST8PDT,M3.2.0,M11.1.0\n", 4096) = 24
_llseek(3, 2818, [2818], SEEK_SET) = 0
close(3) = 0
munmap(0xb78b5000, 4096) = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78b5000
write(1, "Sun Sep 11 09:54:18 PDT 2011\n", 29Sun Sep 11 09:54:18 PDT 2011) = 29
close(1) = 0
munmap(0xb78b5000, 4096) = 0
close(2) = 0
只要你有值得保存的东西:
make
,以避免愚蠢的错误答案 4 :(得分:1)
您可以使用dcc。但是,下次你应该使用Git;)
答案 5 :(得分:0)
您可以尝试使用objdump -d <filename>
进行反汇编。
您还可以使用nm
实用程序查看符号名称,以慢慢记忆并帮助重新编码来源。
商业IDA Pro反汇编程序/调试程序在软件逆向工程中很受欢迎。不幸的是,对二进制文件进行逆向工程是一项缓慢而困难的工作。