Ask Question

Name:
Title:
Your Question:

Answer Question

Name:
Your Answer:
User Submitted Source Code!


Description:
  w
Language: C/C++
Code:
#include <stdio.h>
#include <windows.h>
#include <vector>
#include <set>
#include <algorithm> 
#include <array>
#include <functional> 


using namespace std;

#pragma pack(push,1)
struct ZIPFILERECORD
{
     DWORD sig;
     WORD ver;
     DWORD flags;
     WORD CompressionMethod;
     WORD fileTime;
     WORD fileDate;
     DWORD CRC32;
     DWORD CompressedSize;
     DWORD UnCompressedSize;
     WORD NameLen;
     WORD ExtraFieldLen;
};
#pragma pack(pop)


BYTE ZipName[256];
BYTE file[12];
BYTE plain[12];
DWORD table[256];
DWORD Invtable[256];

ZIPFILERECORD fr;


#define CRC32(x,c)     (((x)>>8)^table[((x)^(c))&0xff])
#define     INVCRC32(x,c)     (((x)<<8)^Invtable[((x)>>24)&0xff]^((c)&0xff))
#define MSB(x)     (((x)>>24)&0xFF)
#define LSB(x)     ((x)&0xff)
#define     INVCONST     0xd94fa8cdU

DWORD key2Table[256][64];

DWORD Read32(FILE *fp)
{
     DWORD r = 0;
     r = fgetc(fp) << 0;
     r += fgetc(fp) << 8;
     r += fgetc(fp) << 16;
     r += fgetc(fp) << 24;
     return r;
}
WORD Read16(FILE *fp)
{
     WORD r = 0;
     r = fgetc(fp) << 0;
     r += fgetc(fp) << 8;
     return r;
}

BYTE DecryptByte(DWORD K)
{
     WORD temp;
     temp = K & 0xffff | 2; //|3 ??
     return (BYTE)(((WORD)(temp * (temp ^ 1)) >> 8));
}

void makeCRCtable()
{
     DWORD i, j, crc;
     DWORD poly = 0xedb88320;
     for (i = 0; i < 256; i++)
     {
          crc = i;
          for (j = 0; j < 8; j++)
          {
               if (crc & 1) crc = (crc >> 1) ^ poly;
               else crc >>= 1;
          }
          table[i] = crc;
          Invtable[crc >> 24] = (crc << 8) ^ i;
     }
}
void makeKey2Table()
{
     int count[256] = {};
     memset(count, 0, 256 * 4);
     for (int i = 0; i<0x10000; i += 4) //하위 2비트는 영향 X. 
     {
          BYTE d = DecryptByte(i);
          key2Table[d][count[d]++] = i;
     }
}

void LoadZip(const char FileName[])
{
     FILE *fp = fopen(FileName, "rb");

     fr.sig = Read32(fp);
     fr.ver = Read16(fp);
     fr.flags = Read16(fp);
     fr.CompressionMethod = Read16(fp);
     fr.fileTime = Read16(fp);
     fr.fileDate = Read16(fp);
     fr.CRC32 = Read32(fp);
     fr.CompressedSize = Read32(fp);
     fr.UnCompressedSize = Read32(fp);
     fr.NameLen = Read16(fp);
     fr.ExtraFieldLen = Read16(fp);
     fread(ZipName, fr.NameLen, 1, fp);
     fseek(fp, fr.ExtraFieldLen, SEEK_CUR);

     fread(file, 12, 1, fp);

     if (fr.flags & 0x8)
     {
          plain[10] = fr.fileTime & 0xff;
          plain[11] = fr.fileTime >> 8;
          for (int i = 0;i<12;i++)
               printf("%02x ", plain[i]);
          printf("\n");
          for (int i = 0;i<12;i++)
               printf("%02x ", file[i]);
          printf("\n");
          //RCRC = fileTime;
     }
     fclose(fp);
}


struct Key
{
     uint32_t key0 = 0x12345678U;
     uint32_t key1 = 0x23456789U;
     uint32_t key2 = 0x34567890U;
     void update_keys(uint8_t c)
     {
          key0 = CRC32(key0, c);
          key1 = (key1 + (key0 & 0xff)) * 0x08088405U + 1;
          key2 = CRC32(key2, key1 >> 24);
     }
     uint8_t decrypt_byte()
     {
          uint16_t temp = (uint16_t)(key2 | 2);
          return (temp*(temp ^ 1)) >> 8;
     }
};


uint32_t key1[12];
uint32_t key2[12];

bool guessKey0()
{
     uint32_t key0 = 0;
     for (int p = 7; p >= 4; p--)
     {
          uint8_t lsb = (key1[p] - 1)*INVCONST - key1[p - 1];
          key0 = (key0 ^ table[lsb^plain[p]]) << 8 | lsb;
     }
     bool ok = true;
     uint32_t k0 = key0;
     for (int i = 4; i<12; i++)
     {
          uint8_t lsb = (key1[i] - 1)*INVCONST - key1[i - 1];
          if ((k0 & 0xff) != lsb)
          {
               ok = false;
               break;
          }
          k0 = k0 >> 8 ^ table[lsb^plain[i]];
     }
     if (ok)
     {
          //printf("Key found! pos=4, key0=%08x, key1=%08x, key2=%08x\n", key0, key1[4], key2[4]);
          uint32_t key0_ = key0;
          uint32_t key1_ = key1[4];
          uint32_t key2_ = key2[4];
          for (int p = 3; p >= 0; p--)
          {
               key2_ = key2_ << 8 ^ Invtable[key2_ >> 24] ^ key1_ >> 24;
               key1_ = (key1_ - 1)*INVCONST - (key0_ & 0xff);
               key0_ = key0_ << 8 ^ Invtable[key0_ >> 24] ^ plain[p];
          }
          printf("Key found! key0=%08x, key1=%08x, key2=%08x\n", key0_, key1_, key2_);
     }

     return ok;
}

bool guessKey1(int p)
{
     if (p == 2)
          return guessKey0();

     uint32_t base;
     int count;
     if (p == 11)
     {
          uint8_t msb = key2[p] << 8 ^ Invtable[key2[p] >> 24] ^ key2[p - 1];
          base = ((msb + 1) << 24) - 1;
          count = 0x1000000;
     }
     else
     {
          base = (key1[p + 1] - 1)*INVCONST;
          count = 0x100;
     }
     uint8_t prevMsb = key2[p - 1] << 8 ^ Invtable[key2[p - 1] >> 24] ^ key2[p - 2];
     for (int i = 0; i<count; i++)
     {
          uint32_t k1 = base - i;
          if (((k1 - 1)*INVCONST) >> 24 == prevMsb &&
               ((k1 - 1)*INVCONST - 0xff) >> 24 == prevMsb)
          {
               key1[p] = k1;
               if (guessKey1(p - 1))
                    return true;
          }
     }
     return false;
}

bool guessKey2(int p)
{
     if (p == -1)
          return guessKey1(11);

     uint32_t inv = Invtable[key2[p + 1] >> 24];
     for (int i = 0; i<64; i++)
     {
          uint32_t left = key2Table[file[p] ^ plain[p]][i];
          uint32_t right = key2[p + 1] << 8 ^ inv;
          if ((left & 0xfc00) == (right & 0xfc00))
          {
               key2[p] = right & 0xffff0000 | left;
               key2[p + 1] = key2[p + 1] & ~0x3 | (left^inv) >> 8 & 0x3;
               if (guessKey2(p - 1))
                    return true;
          }
     }
     return false;
}

void attack()
{
     //올바른 key2[11]이 0xff로 시작하길래 역순으로 정렬시켜서 잘되나 테스트 해봄. 
     set<uint32_t, greater<uint32_t>> key2s;
     for (uint32_t i = 0; i<0x10000; i++)
          for (int j = 0; j<64; j++)
               key2s.insert(i << 16 | key2Table[file[11] ^ plain[11]][j]);
     printf("%d\n", (int)key2s.size());

     DWORD t = GetTickCount();
     DWORD size_ = key2s.size();

     int cnt = 0;

     for (uint32_t k2 : key2s)
     {
          cnt++;
          key2[11] = k2;
          //speed hack
          //if(k2 == 0xFFBBF45C)
          {
               printf("Try key2=%08x (Time : %.2fsec | %lf %%)\n", k2, (GetTickCount() - t) / 1000.0, ((double)cnt / (double)size_)*100.0);
               if (guessKey2(10))
                    exit(0);
          }
     }

}

int main(void)
{
     makeCRCtable();
     makeKey2Table();

     for (int i = 0;i<10;i++)
          plain[i] = rand() & 0xff;
     /*
     key2 에 대해 하위 2비트는 아무대서도 안씀. 무시!

     --> test.zip
     key0( 0) = 0xd087eb63   key1( 0)=0x375335b3   key2( 0)=0x68557e28 | dd
     key0( 1) = 0x96d92f65   key1( 1)=0x6d446e79   key2( 1)=0x06dee061 | 85
     key0( 2) = 0x9f293d8a   key1( 2)=0xfbabb710   key2( 2)=0x10dca4ba | 7b
     key0( 3) = 0x212bdd88   key1( 3)=0xf1c4f5f9   key2( 3)=0xe11e44bc | c1
     key0( 4) = 0x099767f6   key1( 4)=0x77a40eac   key2( 4)=0x0c57057c | 2f
     key0( 5) = 0x83da12a0   key1( 5)=0xc8777c7d   key2( 5)=0xcc002090 | f3
     key0( 6) = 0x92515489   key1( 6)=0x9efc891f   key2( 6)=0xe7742d27 | 8e
     key0( 7) = 0xfb461d31   key1( 7)=0x1c3bee91   key2( 7)=0xb1ec9d09 | e1
     key0( 8) = 0x604bc8c8   key1( 8)=0xb75d90be   key2( 8)=0x2c687216 | 0b
     key0( 9) = 0x10ba3192   key1( 9)=0xde411691   key2( 9)=0x959322f0 | 4f
     key0(10) = 0xee1edb1d   key1(10)=0x0c672967   key2(10)=0xb49e2d15 | ea
     key0(11) = 0x893d353b   key1(11)=0xcc8b582b   key2(11)=0xffbbf45d | 46
     */
     LoadZip("test.zip");
     attack();
     //     Decrypt();
     //printf("%x",INVCRC32(0x5b1b241e,MSB(0x3b9a3e73)));
}
Comments: