/* DON'T EVER WRITE CODE LIKE THIS! It demonstrates all kinds of bad coding practices. It's as wicked, as its authors mind (or a bit less) :-) It is full of bugs and it was designed to be compilable and work on my machine with my bfd, my libopcodes, not on yours :-) */ /* gcc gen3.c -lbfd -lopcodes */ #include #include #include #include char *disbuf=NULL; static int myprint VPARAMS ((void *f, const char *format, ...)) { char *buf, *olddisbuf; VA_OPEN (args, format); VA_FIXEDARG (args, void *, f); VA_FIXEDARG (args, const char *, format); vasprintf (&buf, format, args); if (buf == NULL) exit(2); olddisbuf=disbuf; if (olddisbuf==NULL) asprintf (&disbuf, "%s", buf); else asprintf (&disbuf, "%s%s", olddisbuf, buf); free(buf); free(olddisbuf); VA_CLOSE (args); return 0; } bfd *b; asection *a; unsigned char *data; unsigned long datalen; struct disassemble_info dinfo; disassembler_ftype dis; unsigned long goto_start=0; int bigstop=0; int mydis(unsigned long eip, struct disassemble_info *dinfo) { int r; if (disbuf) free(disbuf); disbuf=NULL; r=dis(eip, dinfo); if (r<0) { printf("Unable to disassemble at 0x%x, aborting\n", eip); exit(4); } return r; } void blank(unsigned long from, unsigned long to) { unsigned long i; for (i=from-a->vma; ivma; i++) data[i]=0x90; } char *check_dummy(unsigned long *rva, int len, struct disassemble_info *dinfo) { unsigned long sum; unsigned long va; int i, l; char *olddisbuf; if (!strstr(disbuf, "pusha")) return NULL; sum=0; /* Is it the exception block? */ for (i=0; i<104; i++) sum=((sum<<13)|(sum>>19)+data[(*rva+len-1-a->vma)+i])^0xd0b3ded0; if (sum==0x7206d84) { char *q; asprintf(&q, "Exception block 0x%x-0x%x", *rva, *rva+len+102); blank(*rva, *rva+len+103); *rva+=len+103; return q; } sum=0; /* Is it the goto block? */ for (i=0; i<74; i++) sum=((sum<<13)|(sum>>19)+data[(*rva+len-1-a->vma)+i])^0xd0b3ded0; if (sum==0x70880ad) { char *q; asprintf(&q, "Exception goto block 0x%x-0x%x", goto_start, *rva+len+72); blank(goto_start, *rva+len+73); *rva+=len+73; /* Replacement goto code: pusha movzx eax,BYTE PTR [esi] mov edi,DWORD PTR [eax+0xe1b991] movzx eax,BYTE PTR [esi+1] mov exa,DWORD PTR [edi+eax] add eax, 9 (so we skip the prologue, except for the popa) jmp eax */ memcpy(data+goto_start-a->vma, "\x60\x0f\xb6\x06\x8b\x3c\x85\x91\xb9\xe1\x00\x0f\xb6\x46\x01\x8b\x04\x87\x83\xc0\x09\xff\xe0", 23); bigstop=1; goto_start=0; return q; } /* Is it the pusha/.../popa dummy code */ va=*rva+len; olddisbuf=disbuf; disbuf=NULL; while(1) { l=mydis(va, dinfo); if (strstr(disbuf, "popa")) { char *q; free(olddisbuf); asprintf(&q, "Dummy block 0x%x-0x%x", *rva, va+l-1); blank(*rva, va+l); *rva=va+l; return q; } else if (strstr(disbuf, "jmp")) { if (data[va-a->vma+l-2]!=0xeb) exit(3); va+=l+*(signed char*)(data+va-a->vma+l-1); } /* Dummy instructions are not allowed to use memory references, except for lea */ else if ((strstr(disbuf, "[") && !strstr(disbuf, "lea")) || strstr(disbuf,"pusha")) { disbuf=olddisbuf; return NULL; } else va+=l; } disbuf=olddisbuf; return NULL; } void display(unsigned long eip, int len) { int i; printf("%x: ", eip); for (i=0; ivma+i]); for (; i<9; i++) printf(" "); printf("%s\n", disbuf); } void dedummify(unsigned long start, unsigned long end) { unsigned long eip, neip; int len; unsigned long etab1=0, etab2=0, encr_start=0; int stop=0; for (eip=start; eip>=start && eipvma)==0x06b60f60) break; /* Does it look like the beginning of an exception-al goto? */ else if (strstr(disbuf, "movzx") && strstr(disbuf, "eax,BYTE PTR [esi]")) { goto_start=eip; neip=eip+len; } /* Or is it the fixing code? */ /* Is it a pusha? If so, check for dummy code */ else if (strstr(disbuf, "pusha")) { char *q; neip=eip; if (q=check_dummy(&neip, len, &dinfo)) { printf("DUMMY (%s)\n", q); eip=neip; if (bigstop) { stop=1; bigstop=0; } continue; } else neip=eip+len; } /* Is it a call ? */ else if (strstr(disbuf, "call ")) { /* Is it the trivial call-pop sequence? */ display(eip, len); eip+=len; neip=eip+*(signed long*)(data+eip-a->vma-4); len=mydis(neip, &dinfo); if (!strstr(disbuf, "pop e")) dedummify(eip, end); eip=neip; continue; } /* Or a conditional jump ? */ else if (strstr(disbuf, "je ") || strstr(disbuf, "jne ")) { display(eip, len); if (data[eip-a->vma+len-2]==0x74 || data[eip-a->vma+len-2]==0x75) neip=eip+len+*(signed char*)(data+eip-a->vma+len-1); else neip=eip+len+*(signed long*)(data+eip-a->vma+len-4); dedummify(eip+len, end); eip=neip; continue; } else if (strstr(disbuf, "ret")) { stop=1; } else if (strstr(disbuf, "jmp")) { char *q=strstr(disbuf, "DWORD PTR [ecx"); if (q) { int i; unsigned long va=strtoul(q+17, 0, 0); neip=eip+len; for (i=0; start<= va+i && va+ivma+i); if (vaa=end) break; dedummify(vaa, end); } len=mydis(neip, &dinfo); } else if (data[eip-a->vma+len-2]==0xeb) neip=eip+len+*(signed char*)(data+eip-a->vma+len-1); else if (data[eip-a->vma+len-5]==0xe9) neip=eip+len+*(signed long*)(data+eip-a->vma+len-4); else { if (etab1!=0 && etab2!=0) { unsigned long ad=eip+len; int llen; do { llen=mydis(ad, &dinfo); } while(check_dummy(&ad, llen, &dinfo)); if (data[ad-a->vma+2]!=0x04) { llen=mydis(eip, &dinfo); stop=1; } else { int i, j; unsigned long start=0, leng=0, k; llen=mydis(eip, &dinfo); printf("Encryption using tables at 0x%x and 0x%x\n", etab1, etab2); for (i=1; i<=3; i++) { unsigned long va=*(unsigned long*)(data+etab1-a->vma+4*i)+a->vma; for (j=0; j<3; j++) { int l=mydis(va, &dinfo); if (strstr(disbuf, "lea")) { char *q=strstr(disbuf, "[ebp+"); if (!q) continue; start=strtoul(q+5, 0, 0); break; } else if (strstr(disbuf, "mov")) { char *q=strstr(disbuf, ","); if (!q) continue; leng=strtoul(q+1, 0, 0); break; } else if (strstr(disbuf, "ret")) break; va+=l; } if (j==3) exit(6); } if (start==0 || leng==0) exit(7); for (k=leng; k>0; k--, start++) data[start-a->vma]^=(k&0xff); etab1=0; etab2=0; len=mydis(ad+3, &dinfo); neip=ad+3+len; len=mydis(neip, &dinfo); if (data[neip-a->vma+len-2]==0xeb) eip=neip+len+*(signed char*)(data+neip-a->vma+len-1); else if (data[neip-a->vma+len-5]==0xe9) eip=neip+len+*(signed long*)(data+neip-a->vma+len-4); if (encr_start!=0) blank(encr_start, eip); encr_start=0; continue; } } } } else if (strstr(disbuf, "xor ")) { encr_start=eip; neip=eip+len; } else if (strstr(disbuf, "mov ")) { char *q=strstr(disbuf, "DWORD PTR [ebp+e"); if (q && strlen(q)>18) { unsigned long et=strtoul(q+21, 0, 10); if (etab1==0) { if (et>=start && etvma)==0xdead) etab1=et; } else if (etab2==0) { if (et>=start && etvma)==0x31000) etab2=et; } } neip=eip+len; } else if (strstr(disbuf, "nop")) { eip+=len; continue; } else { neip=eip+len; } display(eip, len); eip=neip; } } void dumpit() { FILE *f; char buf[300000]; int len; f=fopen("0x90-1.exe", "rb"); len=fread(buf, 1, sizeof(buf), f); fclose(f); memcpy(buf+0x2000, data, datalen); f=fopen("0x90-2.exe", "w+b"); fwrite(buf, 1, len, f); fclose(f); } void detable(unsigned long tva, unsigned long min, unsigned long max) { int i, j; for (i=0; tva+i+4<=max; i+=4) { unsigned long va0=*(unsigned long *)(data+tva-a->vma+i); if (va0=max) break; for (j=0; va0+j+4<=max; j+=4) { unsigned long va=*(unsigned long *)(data+va0-a->vma+j); if (min<=va && vavma]==0x64 || data[va-a->vma]==0x60)) { printf("Cleaning up function at %x\n", va); if (data[va-a->vma]==0x64) memset(data+va-a->vma, 0x90, 9); bigstop=0; dedummify(va, max); } } } } int main() { char **m; bfd_arch_info_type *ainfo; atexit(dumpit); bfd_init(); b=bfd_openr("0x90-1.exe", NULL); bfd_check_format_matches (b, bfd_object, &m); INIT_DISASSEMBLE_INFO(dinfo, stdout, fprintf); b->arch_info=bfd_scan_arch ("i386"); dis=disassembler(b); a=b->sections->next; /* We are interested only in second section */ dinfo.flavour = bfd_get_flavour (b); dinfo.arch = bfd_get_arch (b); dinfo.mach = bfd_get_mach (b); dinfo.disassembler_options = "intel"; dinfo.octets_per_byte = 1; datalen=dinfo.buffer_length=bfd_get_section_size_before_reloc(a); data=dinfo.buffer=(bfd_byte*)malloc(datalen); bfd_get_section_contents (b, a, data, 0, datalen); dinfo.buffer_vma=a->vma; dinfo.section=a; dinfo.fprintf_func=(fprintf_ftype)myprint; dinfo.stream=NULL; dedummify(a->vma, a->vma+dinfo.buffer_length); detable(0xe1b991,a->vma, a->vma+dinfo.buffer_length); return 0; }