在做逆向作业的时候遇到一个问题:把从内存读回的数据用
char a[1000]
LOOP
printf("%x",a);
的方式输出到屏幕,再转储成二进制的话,总会出现数据丢失的情况。由于输出文件是一个MP3文件,一旦有数据丢失就意味着文件结构破坏,无法解析。
后来发现使用
LOOP
printf("%c",a);
的方式打印,直接就可以得到完好的二进制文件,./decrypt2 > file.mp3
的结果甚至可以直接播放。于是研究了一下使用printf格式化为%x和%c的差异。
#include <stdio.h>
int main()
{
int a = 0x99;
unsigned char b[4] = {0x4,0x0,0x0,0x1};
printf("int a = %x\n", a);
for(int i = 0; i < 4; i++)
printf("%x", b[i]);
for(int i = 0; i < 4; i++)
printf("%c", b[i]);
return 0;
}
用%x输出的结果是4001
,而用%c输出的结果是04000001
。由于%x是按照int类型输出,因此并不会理会数据原本的宽度,直接打印。因此如果使用%x格式,则一定要记好原先的宽度,使用诸如%02x的方式输出。
当然,%c输出的是直接的binary,也就是ASCII字符,屏幕打印出来看着像乱码,在开头提到的环境中一步到位。如果是需要得到数字值,则必须使用%x辅以数值宽度的方式。
LD_PRELOAD的作业非常有趣,是将一个二进制文件中的一段运行时数据偷出来。解密函数用静态编译,无缘动手,居然最终的破题是在程序最后不起眼的free
函数。通过preload自己写的free
动态库,覆盖libc的原函数,使得在源程序在调用free
函数的时候自动将数据段打印出来。
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
//#include <evp.h>
/*
typedef int (*orig_decryptupdate_type)(void *ctx, unsigned char *out, int *outl, \
const unsigned char *in, int inl);
int EVP_DecryptUpdate(void *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl)
{
printf("I'm in!\n");
orig_decryptupdate_type orig_DecryptUpdate;
orig_DecryptUpdate = (orig_decryptupdate_type)dlsym(RTLD_NEXT, "EVP_DecryptUpdate");
printf("input: %s\n", in);
printf("output: %s\n\n", out);
return orig_DecryptUpdate(ctx, out, outl, in, inl);
}
*/
typedef void (*orig_free_type)(void *ptr);
void free(void *ptr)
{
long len = 0x98CA0-0x6050;
unsigned char out[0x98ca0-0x6050];
unsigned char *p = ptr;
orig_free_type orig_free;
orig_free = (orig_free_type)dlsym(RTLD_NEXT, "free");
//printf("\n+++ I'm in `free`! +++\n");
if(*p == 0x49) {
memcpy(out, (unsigned char*)p, len);
//printf("\n%ld\n",strlen(out));
for(long i = 0; i < len; i++)
{
printf("%x",(unsigned char)out[i]);
}
}
orig_free(ptr);
}
编译和设置
$ gcc -shared -fPIC decrypt-dlib.c -o decrypt-dlib.so -ldl
$ export LD_PRELOAD="$PWD/decrypt-dlib.so"
运行
$ ./decrypt2 > free_bin.mp3
播放即可。
Comments