⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 2c.c

📁 twocrypt(2c)是一个 PoC工具
💻 C
字号:
/*   2c.c - main entry point   -----------------------   Copyright (C) 2003 by Michal Zalewski <lcamtuf@coredump.cx> */#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <termios.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/fcntl.h>#include <openssl/md5.h>#include <assert.h>#include <string.h>#include <errno.h>#include <getopt.h>#include "types.h"#include "config.h"#include "lzf.h"#include "macros.h"#define STR_CNT 5struct bitstream {  _u8  buf[KEYSIZE];		// I/O or key buffer  _s32 buftop;			// Upper usable buffer size limit  _u32 bitoff;			// Bit offset selector  _u32 fd,len;			// file descriptor, file length  _u32 kID;			// key generation stuff  _u64 kCARRY;	 		// key generation stuff  _u8* pass;			// passphrase} bs[STR_CNT];_u32 random_d;void volatile wipe_memory(void* volatile ptr,_u32 cnt) {  if (!ptr) return;  cnt = (cnt + 3)/4;  asm volatile(    "movl $0xdeadbeef,%%eax ; rep stosl"    : "=D" (ptr), "=c" (cnt)    : "D" (ptr), "c" (cnt)    : "memory", "eax");}void register_stream(_u8 id,_u32 fd,_u32 kID,_u8* pass,_u32 len) {  if (id >= STR_CNT) fatal("register_stream id >= %u\n",STR_CNT);  bs[id].fd=fd;  bs[id].bitoff=0;  bs[id].buftop=0;  bs[id].kID=kID;  bs[id].len=len;  bs[id].kCARRY=0;  bs[id].pass=pass;}_u8 get_bit(_u8 sid) {  _u8 ret;  if ((bs[sid].bitoff >> 3) >= bs[sid].buftop) {    bs[sid].buftop = read(bs[sid].fd,bs[sid].buf,KEYSIZE);    if (bs[sid].buftop <= 0) return 255;    bs[sid].bitoff = 0;  }  ret = (bs[sid].buf[bs[sid].bitoff>>3] & (1<<(bs[sid].bitoff % 8))) != 0;  bs[sid].bitoff++;  return ret;}void get_basekey(_u8 sid);_u8 get_keybit(_u8 sid) {  _u8 ret;  if ((bs[sid].bitoff >> 3) >= bs[sid].buftop) {    get_basekey(sid);    bs[sid].buftop = KEYSIZE;    bs[sid].bitoff = 0;  }  ret = (bs[sid].buf[bs[sid].bitoff>>3] & (1<<(bs[sid].bitoff % 8))) != 0;  bs[sid].bitoff++;  return ret;}void put_bit(_u8 sid,_u8 val) {  if (val==255) {    if (bs[sid].bitoff) {      if (bs[sid].bitoff & 8) bs[sid].bitoff += 8;      ckwrite(bs[sid].fd,bs[sid].buf,bs[sid].bitoff >> 3);      bs[sid].bitoff = 0;    }    return;  }  if ((bs[sid].bitoff >> 3) == KEYSIZE) {    ckwrite(bs[sid].fd,bs[sid].buf,KEYSIZE);    bs[sid].bitoff = 0;  }  if (val) bs[sid].buf[bs[sid].bitoff>>3] |= (1<<(bs[sid].bitoff % 8));    else bs[sid].buf[bs[sid].bitoff>>3] &= ~(1<<(bs[sid].bitoff % 8));  bs[sid].bitoff++;  return;}void get_basekey(_u8 sid) {  _u32 i;  MD5_CTX k;  assert(!(KEYSIZE  % 8));  for (i=0;i< KEYSIZE>>3;i++) {    MD5_Init(&k);    MD5_Update(&k,bs[sid].pass,strlen(bs[sid].pass));    MD5_Update(&k,&bs[sid].kCARRY,8);    MD5_Update(&k,&bs[sid].kID,4);    MD5_Final(bs[sid].buf+(i<<3),&k);    bs[sid].kCARRY = *(_u64*)(bs[sid].buf+(i<<3));  }}void term_echo(_u8 state) {  struct termios tios;  ioctl(0,TCGETS,&tios);  if (state) tios.c_lflag |= ECHO; else tios.c_lflag &= ~ECHO;  ioctl(0,TCSETS,&tios);}_u8* get_password(_u8* what) {  static _u8 pass_buf[MAX_PASS+1];  _u8* p;retry:  term_echo(0);  debug("[+] Enter %s password: ",what);  fgets(pass_buf,MAX_PASS,stdin);  term_echo(1);  debug("\n");  if ((p=strrchr(pass_buf,'\n'))) *p=0; else    fatal("[-] Password incomplete or too long.\n");  if (!pass_buf[0]) fatal("[-] Password empty.\n");  if (strlen(pass_buf) < MIN_PASS) {    debug("Password too short, use at least %u characters.\n",MIN_PASS);    goto retry;  }  return strdup(pass_buf);}void compress_file(_u32 infd,_u32 outfd,_u32 total) {  struct secthdr s;  _u8  buf[CMP_BLK],cbuf[CMP_BLK];  _u32 i,c,sofar=0,tlen=0;  while ((i=read(infd,buf,CMP_BLK))>0) {    if (sofar >= total) break;    if (sofar + i >= total) i = total - sofar;    sofar += i;    c=lzf(buf,i,cbuf,i);    if (!c) {      s.type=BLK_UNCOMP;      s.len =i;      ckwrite(outfd,&s,sizeof(struct secthdr));      ckwrite(outfd,buf,i);      tlen += i + sizeof(struct secthdr);    } else {      s.type=BLK_COMP;      s.len =c;      ckwrite(outfd,&s,sizeof(struct secthdr));      ckwrite(outfd,cbuf,c);      tlen += c + sizeof(struct secthdr);    }     debug("\rProgress: [");    for (i=0;i<sofar * 40 / total;i++) debug("*");    for (;i<40;i++) debug(" ");    debug("]");  }  debug("\r%70s\r","");  wipe_memory(buf,CMP_BLK);  wipe_memory(cbuf,CMP_BLK);  // Remove last ) to crash gcc with sig11. Yeah!  debug("[*] Compressed size: %0.02f%%\n",(tlen*100.0)/((float)sofar));}void uncompress_file(_u32 infd,_u32 outfd) {  struct secthdr s;  _u8  buf[CMP_BLK],ubuf[CMP_BLK];  _u32 i,c;  while ((i=read(infd,&s,sizeof(struct secthdr)))>0) {    if (s.len > CMP_BLK || !s.len)       fatal("[-] Compression header corrupted 1 (bad password?).\n");    if (read(infd,buf,s.len) != s.len)      fatal("[-] Compressed data corrupted 2 (bad password?).\n");    if (s.type == BLK_COMP) {      c=unlzf(buf,s.len,ubuf,CMP_BLK);      ckwrite(outfd,ubuf,c);    } else if (s.type == BLK_UNCOMP) {      ckwrite(outfd,buf,s.len);    } else fatal("[-] Compression header corrupted 3 (bad password?).\n");  }}void encrypt_file(_u8 sid,_u32 of) {  _u8  ibuf[KEYSIZE];  _u32 c,i;  _u32 sT=4;  _u32 total=0;  *(_u32*)ibuf = bs[sid].len;  while (total < bs[sid].len + 4) {    c=read(bs[sid].fd,ibuf+sT,KEYSIZE-sT);    if (c<=0) fatal("\n[-] Whoops, unexpected EOF in encrypt() - %d/%d\n",                    total,bs[sid].len+4);    c+=sT; sT=0;    get_basekey(sid);    if (total + c >= bs[sid].len + 4) c = bs[sid].len + 4 - total;    for (i=0;i<c;i++) ibuf[i] ^= bs[sid].buf[i];    ckwrite(of,ibuf,c);    total += c;    debug("\rProgress: [");    for (i=0;i<total * 40 / bs[sid].len;i++) debug("*");    for (;i<40;i++) debug(" ");    debug("]");  }  debug("\r%70s\r","");  wipe_memory(ibuf,CMP_BLK);}_u32 decrypt_file(_u8 sid,_u32 of) {  _u8  ibuf[KEYSIZE];  _u32 c,i,cT=0;  _u32 total=0;  while (total < bs[sid].len) {    c=read(bs[sid].fd,ibuf,KEYSIZE);    if (c<=0) fatal("\n[-] Whoops, unexpected EOF in decrypt() - %d/%d.\n",                    total,bs[sid].len);    get_basekey(sid);    for (i=0;i<c;i++) ibuf[i] ^= bs[sid].buf[i];    if (!total) {      cT=*(_u32*)ibuf;      ckwrite(of,ibuf+4,c-4);    } else ckwrite(of,ibuf,c);    total += c;    debug("\rProgress: [");    for (i=0;i<total * 40 / bs[sid].len;i++) debug("*");    for (;i<40;i++) debug(" ");    debug("]");  }  debug("\r%70s\r","");  return cT;}void wipe_file(_u32 fd) {  _u8  zerobuf[4096];  _u8  pass;  debug("[+] Wiping temporary file: ");  for (pass=0;pass<8;pass++) {    _s32 siz = getlen(fd);    debug("%d ",pass);    fsync(fd);    if (read(random_d,zerobuf,4096)!=4096) debug("*OOOPS!* ");    while (siz > 0) {      write(fd,zerobuf,(siz>4096)?4096:siz);      siz -= 4096;    }    fsync(fd);  }  debug("(done)\n");}// Slow, but we can afford it._u32 get_random(void) {  _u32 ret;  ckread(random_d,&ret,4);  return ret;}void usage(_u8* name) {  debug("Usage: %s -o ofile -e file1 file2  - combine and encrypt files\n"        "       %s -o ofile -e file1        - encrypt and pad with random\n"        "       %s -o ofile -d file1        - decrypt one component\n\n",	name,name,name);  exit(2);}int main(int argc,char* argv[]) {  _u8   encrypt=2;  _s8   opt,clin;  _u32  bit_count=0;  _u32  i;  _u8   *outfile=0,*pass1,*pass2,*infile1,*infile2;  _u32  flen1,flen2=0;  _u32  data_s1,data_s2;  // Working descriptors:  _s32  out_d,in1_d,in2_d,tmp1_d,tmp2_d,cmp_d;    debug("2c by <lcamtuf@coredump.cx>\n");  if (argc<2) usage(argv[0]);  while ((opt=getopt(argc,(void*)argv, "+edo:"))!=EOF)    switch(opt) {      case 'e': encrypt=1; break;      case 'o': outfile=optarg; break;      case 'd': encrypt=0; break;      default:  usage(argv[0]);    }  if (encrypt == 2)    usage(argv[0]);  if (!outfile)	       usage(argv[0]);  if (!(argc-optind))  usage(argv[0]);  if (argc-optind > 2) usage(argv[0]);  unlink(outfile);  out_d=ckopen(outfile,O_RDWR|O_EXCL|O_CREAT,0600);  infile1=argv[optind];  infile2=argv[optind+1];  if (mlockall(MCL_FUTURE|MCL_CURRENT))    debug("[!] Warning: can't lock physical memory.\n");  random_d = ckopen(RND_SOURCE,O_RDONLY);  debug("[*] Using %s for random pad data...\n",RND_SOURCE);  if (get_random() == get_random())     debug("[-] Faulty randomness source or a really bad day.\n");  if (encrypt) {     in1_d = ckopen(infile1,O_RDONLY);    flen1 = getlen(in1_d);    if (!infile2) {      _u32 bogus[4] = { get_random(), get_random(), get_random(), 0 };      // We use /dev/urandom because we hardly need fresh entropy for this.      in2_d = dup(random_d);      if (in2_d < 0) fatal("[-] dup() failed: %s\n",strerror(errno));      flen2 = flen1;      debug("[*] Source 1: %s (%u bytes)\n"            "    Source 2: <random pad>\n",infile1,flen1);      pass1 = get_password(infile1);      pass2 = strdup((_u8*)bogus);     } else {      in2_d = ckopen(infile2,O_RDONLY);      flen2 = getlen(in2_d);      debug("[*] Source 1: %s (%u bytes)\n"            "    Source 2: %s (%u bytes)\n",infile1,flen1,infile2,flen2);      if (flen1 < flen2)         fatal("[-] Second file is larger. Data hiding would be evident.\n");      pass1 = get_password(infile1);      pass2 = get_password(infile2);    }    if (flen1 >= 0x10000000) fatal("[-] Input file too big.\n");    debug("[+] Compressing input data source 1...\n");    cmp_d=cktemp();    compress_file(in1_d,cmp_d,flen1);    flen1 = getlen(cmp_d);    close(in1_d); in1_d=cmp_d;    debug("[+] Encrypting input data source 1...\n");    register_stream(0,in1_d,CFILE1_ID,pass1,flen1);    tmp1_d=cktemp(); encrypt_file(0,tmp1_d);     wipe_file(cmp_d);    flen1 += 4; close(in1_d); lseek(tmp1_d,0,SEEK_SET);    register_stream(0,tmp1_d,0,0,0);  	  // 0 - encrypted file1    // If using random, spoof the compression ratio of the original    // file.    if (!infile2) flen2=flen1;    debug("[+] Compressing input data source 2...\n");    cmp_d=cktemp();    compress_file(in2_d,cmp_d,flen2);    if (infile2) {      flen2 = getlen(cmp_d);       if (flen2 > flen1) {        debug("[-] Second file compressed well and is larger than "              "the first one.\n    Second file cannot be larger, data hiding"              " would be evident.\n");        wipe_file(cmp_d);        exit(3);      }    } else {      ftruncate(cmp_d,flen1);      lseek(cmp_d,0,SEEK_SET);    }    close(in2_d); in2_d=cmp_d;    debug("[+] Encrypting input data source 2...\n");    register_stream(1,in2_d,CFILE2_ID,pass2,flen2);    tmp2_d=cktemp(); encrypt_file(1,tmp2_d);     wipe_file(cmp_d);    flen2 += 4; close(in2_d); lseek(tmp2_d,0,SEEK_SET);    register_stream(1,tmp2_d,0,0,0);    // 1 - encrypted file2    // 2 - selector bitstream generated with pass1    register_stream(2,0,CSTREAM_ID,pass1,0);     // 3 - oputput file    register_stream(3,out_d,0,0,0);    // 4 - /dev/urandom for stuffing    in1_d=ckdup(random_d);    register_stream(4,in1_d,0,0,0);    // Calculate bit sizes    data_s1 = flen1 * 8;    data_s2 = flen2 * 8;    debug("[+] Data scrambling in progress...\n");    clin=0;    debug(".------------------------------------------.\n| ");    while (data_s1 || data_s2) {      i=get_keybit(2);      if (i) {         if (data_s1) { put_bit(3,get_bit(0)); data_s1--; } 	  else put_bit(3,get_bit(4));      } else { 	if (data_s2) { put_bit(3,get_bit(1)); data_s2--; } 	   else put_bit(3,get_bit(4));      }      bit_count++;      // Sometimes, we might want to display some stuff...      if (!((bit_count / 800) % 50)) {        if (i) debug("O"); else debug(" ");        if (!(bit_count % 40)) {          if (!(bit_count % 400)) {            debug(" |\n`------------------------------------------'"                  "\r\033[A\033[A\033[A\033[A\033[A"                  "\033[A\033[A\033[A\033[A\033[A| ");            clin=0;          } else { debug(" |\n| "); clin++; }        }      }    }    for (i=0;i<11-clin;i++) debug("\n");    flen1 = get_random() % RANDOM_PAD;    // Add some more non-key, non-filesize random padding.    for (i=0;i<flen1;i++) put_bit(3,get_bit(4));    put_bit(3,255);    debug("[+] Mixed %u stream bits, %d trailing.\n",bit_count,flen1);    close(out_d);  } else {    in1_d = ckopen(infile1,O_RDONLY);    flen1 = getlen(in1_d);    debug("[*] File %s opened successfully, credentials please.\n",infile1);    pass1 = get_password("main");    // 0 - original scrambled file    register_stream(0,in1_d,0,0,0);    // 1 - selector bitstream generated with pass1    register_stream(1,0,CSTREAM_ID,pass1,0);    // 2 - temporary output file 1    tmp1_d = cktemp();    register_stream(2,tmp1_d,0,0,0);    // 3 - temporary output file 2    tmp2_d = cktemp();    register_stream(3,tmp2_d,0,0,0);    debug("[+] Splitting data stream...\n");    flen1 = 0; flen2 = 0;    while ((i=get_bit(0))!=255) {      if (get_keybit(1)) {        flen1++; put_bit(2,i);       } else {        flen2++; put_bit(3,i);       }      if ((flen1 % 1717)==1) debug("\rBins: %u / %u bits...",flen1,flen2);    }    put_bit(2,255); put_bit(3,255);    close(in1_d);    debug("\r%40s\r","");    cmp_d=cktemp();    // 0 - primary chunk    lseek(tmp1_d,0,SEEK_SET);    flen1 >>= 3;    register_stream(0,tmp1_d,CFILE1_ID,pass1,flen1);    i=decrypt_file(0,cmp_d);    if (i > flen1 || i < MIN_SIZE) {      debug("[-] The output file appears to be corrupted (bad password?).\n");      unlink(outfile);      exit(3);    }    close(tmp1_d);    ftruncate(cmp_d,i);    lseek(cmp_d,0,SEEK_SET);    uncompress_file(cmp_d,out_d);    close(cmp_d); close(out_d);    debug("[+] Main chunk deciphered. Any secondary file? Hit RETURN for none.\n");    pass2 = get_password("secondary");    infile2 = malloc(strlen(outfile)+4);    sprintf(infile2,"%s-2",outfile);    outfile = infile2;    unlink(outfile);    out_d=ckopen(outfile,O_RDWR|O_EXCL|O_CREAT,0600);    debug("[*] Saving secondary data to %s...\n",outfile);    // 0 - secondary chunk    cmp_d = cktemp();    lseek(tmp2_d,0,SEEK_SET);    flen2 >>= 3;    register_stream(0,tmp2_d,CFILE2_ID,pass2,flen2);    i=decrypt_file(0,cmp_d);    if (i > flen2 || i < MIN_SIZE) {      debug("[-] The output file appears to be corrupted (no file at all?).\n");      unlink(outfile);      exit(3);    }    close(tmp2_d);    ftruncate(cmp_d,i);    lseek(cmp_d,0,SEEK_SET);    uncompress_file(cmp_d,out_d);    close(cmp_d); close(out_d);   }  debug("[*] Done, have a nice day, and remember to wipe the data.\n");  for (i=0;i<STR_CNT;i++) wipe_memory(bs[i].buf,KEYSIZE);  for (i=0;i<STR_CNT;i++)     if (bs[i].pass) wipe_memory(bs[i].pass,strlen(bs[i].pass));  exit(0);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -