V&NCTF 2023 RE WP

只做出了分数较低的三道题

一、PZGalaxy

JS逆向题
修改js源码,直接爆破,提交即可拿到flag
<!DOCTYPE html>
<html>
  <head>
    <meta charset=UTF-8 />
    <link rel="stylesheet" type="text/css" href="styles.css" />
    <link href="https://fonts.googleapis.com/css?family=Raleway&display=swap" rel="stylesheet"> 
    <title>P.Z Galaxy</title>
    <link rel="icon" href="Star.png" type ="image/x-icon">
  </head>
  <body>
    <div class="text-box">
      <center><div class="heading" style="color:#3E3F4C">Welcome to VNCTF2023</div></center>
      <div id = "demo" style="color:#BE98AA"></div>

    <center>
      <form id="form">
        <input id="date" type="text">
        <button type="submit">Do it!</button>
      </form>
    </center>

    <script src="three.min.js"></script>
    <script>
    let scene, camera, renderer, stars, starGeo;
    

    function Galaxy(image, size) {

      scene = new THREE.Scene();

      camera = new THREE.PerspectiveCamera(60,window.innerWidth / window.innerHeight, 1, 1000);
      camera.position.z = 1;
      camera.rotation.x = Math.PI/2;

      renderer = new THREE.WebGLRenderer();
      renderer.setSize(window.innerWidth, window.innerHeight);
      document.body.appendChild(renderer.domElement);

      starGeo = new THREE.Geometry();
      for(let i=0;i<6000;i++) {
        star = new THREE.Vector3(
          Math.random() * 600 - 300,
          Math.random() * 600 - 300,
          Math.random() * 600 - 300
        );
        star.velocity = 0;
        star.acceleration = 0.0008;
        starGeo.vertices.push(star);
      }

      let sprite = new THREE.TextureLoader().load( image );
      let starMaterial = new THREE.PointsMaterial({
        color: 0xaaaaaa,
        size: size,
        map: sprite
      });

      stars = new THREE.Points(starGeo,starMaterial);
      scene.add(stars);

      window.addEventListener("resize", onWindowResize, false);

      animate(); 
    }
    Galaxy('Star.png', 2);


    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
      }


    function animate() {
      starGeo.vertices.forEach(p => {
        p.velocity += p.acceleration
        p.y -= p.velocity;
        
        if (p.y < -200) {
          p.y = 200;
          p.velocity = 0;
        }
      });
      starGeo.verticesNeedUpdate = true;
      stars.rotation.y +=0.002;
    
      renderer.render(scene, camera);
      requestAnimationFrame(animate);
    }
    

    var saying = "Here is PZGalaxy, Enjoy it."
    var i = 0;
    function typing(){
      var demo = document.getElementById('demo')
      if (i <= saying.length) {
        demo.innerHTML = saying.slice(0, i++);
        setTimeout("typing()", 150);
      }else{
        demo.innerHTML = saying;
      }
    }
    typing();


    function Leaf(k, p) {
      var s = [], j = 0, x, res = '';
      for (var i = 0; i < 256; i++) {
        s[i] = i;
      }
      for (i = 0; i < 256; i++) {
        j = (j + s[i] + k.charCodeAt(i % k.length)) % 256;
        x = s[i];
        s[i] = s[j];
        s[j] = x;
      }
      i = 0;
      j = 0;
      for (var y = 0; y < p.length; y++) {
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;
        x = s[i];
        s[i] = s[j];
        s[j] = x;
        res += String.fromCharCode(p.charCodeAt(y) ^ s[(s[i] + s[j]) % 256]);
      }
      return res;
    }

    form.addEventListener("submit", (ev) => {
      ev.preventDefault();
    var enc = ['¦', 'p', ':', 'Ü', '\x92', 'Ã', '\x97', 'ó', '\x1A', 'ß', '\b', 'Ö', 'A', ' ', '5', '\x90', '{', '\x06', 'Ô', '÷', 's', '_', '\x1D', ':', 'I', 'L', 'C', 'X', 'Ñ', '¹', 'O', '\x99', '\x85', '3', 'à', 'i', '|'];
        for(var a = 0x30;a<0x39;a++){
            for(var b = 0x30;b<0x39;b++){
                for(var c = 0x30;c<0x39;c++){
                    for(var d = 0x30;d<0x39;d++){
                            var date = "2023" + String.fromCharCode(a) + String.fromCharCode(b) + String.fromCharCode(c)+String.fromCharCode(d)
                            // alert(date)
                            flag = Leaf(date, enc.join(''));

                            if (flag.substring(0, 4) ==  "flag"){
                                Galaxy('Neko.jpg', 50);
                                alert(flag)
                            }

                        }
                }
            }
        }
        alert("nononononono!!!!!!!1111")
        
    })

    
    </script>
  </body>
</html>
 
0
flag{HitYourSoulAndSeeYouInTheGalaxy}
 

二、confuse_re

魔改AES EBC 128 加密 + 作者自定义的混淆  
-------------------------------------------------------------------------2023--2--22更正------------------------------------------------------------------------------
是魔改AES CBC 128加密
对AES加密掌握不太好,在这题上浪费了好多时间,tnnd

1、魔改addRoundKey

0

2、魔改keyExpansion ??

可能魔改了,没大分析,我直接提取扩展后的密钥流进行的解密

3、exp:

#include <stdint.h>
#include <stdio.h>
#include <string.h>

typedef struct {
    uint32_t eK[44], dK[44];    // encKey, decKey
    int Nr; // 10 rounds
}AesKey;

#define BLOCKSIZE 16  //AES-128分组长度为16字节

// uint8_t y[4] -> uint32_t x
#define LOAD32H(x, y) \
  do { (x) = ((uint32_t)((y)[0] & 0xff)<<24) | ((uint32_t)((y)[1] & 0xff)<<16) | \
             ((uint32_t)((y)[2] & 0xff)<<8)  | ((uint32_t)((y)[3] & 0xff));} while(0)

// uint32_t x -> uint8_t y[4]
#define STORE32H(x, y) \
  do { (y)[0] = (uint8_t)(((x)>>24) & 0xff); (y)[1] = (uint8_t)(((x)>>16) & 0xff);   \
       (y)[2] = (uint8_t)(((x)>>8) & 0xff); (y)[3] = (uint8_t)((x) & 0xff); } while(0)

// 从uint32_t x中提取从低位开始的第n个字节
#define BYTE(x, n) (((x) >> (8 * (n))) & 0xff)

/* used for keyExpansion */
// 字节替换然后循环左移1位
#define MIX(x) (((S[BYTE(x, 2)] << 24) & 0xff000000) ^ ((S[BYTE(x, 1)] << 16) & 0xff0000) ^ \
                ((S[BYTE(x, 0)] << 8) & 0xff00) ^ (S[BYTE(x, 3)] & 0xff))

// uint32_t x循环左移n位
#define ROF32(x, n)  (((x) << (n)) | ((x) >> (32-(n))))
// uint32_t x循环右移n位
#define ROR32(x, n)  (((x) >> (n)) | ((x) << (32-(n))))

/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
// AES-128轮常量
static const uint32_t rcon[10] = {
//        0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, 0x10000000UL,
//        0x20000000UL, 0x40000000UL, 0x80000000UL, 0x1B000000UL, 0x36000000UL
        0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
};
// S盒
unsigned char S[256] = {
        0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
        0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
        0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
        0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
        0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
        0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
        0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
        0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
        0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
        0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
        0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
        0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
        0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
        0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
        0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
        0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};

//逆S盒
unsigned char inv_S[256] = {
        0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
        0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
        0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
        0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
        0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
        0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
        0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
        0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
        0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
        0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
        0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
        0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
        0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
        0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
        0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
        0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
};

/* copy in[16] to state[4][4] */
int loadStateArray(uint8_t(*state)[4], const uint8_t* in) {
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            state[j][i] = *in++;
        }
    }
    return 0;
}

/* copy state[4][4] to out[16] */
int storeStateArray(uint8_t(*state)[4], uint8_t* out) {
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            *out++ = state[j][i];
        }
    }
    return 0;
}
//秘钥扩展
int keyExpansion(const uint8_t* key, uint32_t keyLen, AesKey* aesKey) {

    if (NULL == key || NULL == aesKey) {
        printf("keyExpansion param is NULL\n");
        return -1;
    }

    if (keyLen != 16) {
        printf("keyExpansion keyLen = %d, Not support.\n", keyLen);
        return -1;
    }

    uint32_t* w = aesKey->eK;  //加密秘钥
    uint32_t* v = aesKey->dK;  //解密秘钥

    /* keyLen is 16 Bytes, generate uint32_t W[44]. */

    /* W[0-3] */
    for (int i = 0; i < 4; ++i) {
        LOAD32H(w[i], key + 4 * i);
    }

    /* W[4-43] */

    
    uint32_t data[45] = {
    0xF87F9DCA, 0x049009A4, 0x6106D4FA, 0x5A773BE9, 0xE6C16829, 0xE251618D, 0x8357B577, 0xD9208E9E, 
    0xEDF4DF32, 0x0FA5BEBF, 0x8CF20BC8, 0x55D28556, 0x5C086AA1, 0x53ADD41E, 0xDF5FDFD6, 0x8A8D5A80, 
    0x91763717, 0xC2DBE309, 0x1D843CDF, 0x9709665F, 0x5EFE3634, 0x9C25D53D, 0x81A1E9E2, 0x16A88FBD, 
    0x24B9F467, 0xB89C215A, 0x393DC8B8, 0x2F954705, 0x4FACDE87, 0xF730FFDD, 0xCE0D3765, 0xE1987060, 
    0x9F549856, 0x6864678B, 0xA66950EE, 0x47F1208E, 0x86F439FA, 0xEE905E71, 0x48F90E9F, 0x0F082E11, 
    0x048209FD, 0xEA12578C, 0xA2EB5913, 0xADE37702, 0x004E5018
    };
    for(int i = 0;i<=44;i++) w[i] = data[i];
    
    for (int i = 0; i < 10; ++i) {
        w += 4;
    }
    w = aesKey->eK + 44 - 4;
    //解密秘钥矩阵为加密秘钥矩阵的倒序,方便使用,把ek的11个矩阵倒序排列分配给dk作为解密秘钥
    //即dk[0-3]=ek[41-44], dk[4-7]=ek[37-40]... dk[41-44]=ek[0-3]
    for (int j = 0; j < 11; ++j) {

        for (int i = 0; i < 4; ++i) {
            v[i] = w[i];
        }
        w -= 4;
        v += 4;
    }

    
    return 0;
}



int addRoundKey(uint8_t(*state)[4], const uint32_t* key) {
    uint8_t k[4][4];

    /* i: row, j: col */
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            k[i][j] = (uint8_t)BYTE(key[j], i);  /* 把 uint32 key[4] 先转换为矩阵 uint8 k[4][4] */
//            printf("0x%x  0x%x\n",state[i][j],k[i][j] );
            state[i][j] ^= k[i][j] ^ 0x23;
        }
    }

    return 0;
}

//字节替换
int subBytes(uint8_t(*state)[4]) {
    /* i: row, j: col */
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            state[i][j] = S[state[i][j]]; //直接使用原始字节作为S盒数据下标
        }
    }

    return 0;
}

//逆字节替换
int invSubBytes(uint8_t(*state)[4]) {
    /* i: row, j: col */
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            state[i][j] = inv_S[state[i][j]];
        }
    }
    return 0;
}

//行移位
int shiftRows(uint8_t(*state)[4]) {
    uint32_t block[4] = { 0 };

    /* i: row */
    for (int i = 0; i < 4; ++i) {
        //便于行循环移位,先把一行4字节拼成uint_32结构,移位后再转成独立的4个字节uint8_t
        LOAD32H(block[i], state[i]);
        block[i] = ROF32(block[i], 8 * i);
        STORE32H(block[i], state[i]);
    }

    return 0;
}

//逆行移位
int invShiftRows(uint8_t(*state)[4]) {
    uint32_t block[4] = { 0 };

    /* i: row */
    for (int i = 0; i < 4; ++i) {
        LOAD32H(block[i], state[i]);
        block[i] = ROR32(block[i], 8 * i);
        STORE32H(block[i], state[i]);
    }

    return 0;
}

/* Galois Field (256) Multiplication of two Bytes */
// 两字节的伽罗华域乘法运算
uint8_t GMul(uint8_t u, uint8_t v) {
    uint8_t p = 0;

    for (int i = 0; i < 8; ++i) {
        if (u & 0x01) {    //
            p ^= v;
        }

        int flag = (v & 0x80);
        v <<= 1;
        if (flag) {
            v ^= 0x1B; /* x^8 + x^4 + x^3 + x + 1 */
        }

        u >>= 1;
    }

    return p;
}

// 列混合
int mixColumns(uint8_t(*state)[4]) {
    uint8_t tmp[4][4];
    uint8_t M[4][4] = { {0x02, 0x03, 0x01, 0x01},
                       {0x01, 0x02, 0x03, 0x01},
                       {0x01, 0x01, 0x02, 0x03},
                       {0x03, 0x01, 0x01, 0x02} };

    /* copy state[4][4] to tmp[4][4] */
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            tmp[i][j] = state[i][j];
        }
    }

    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {  //伽罗华域加法和乘法
        
        
            state[i][j] = GMul(M[i][0], tmp[0][j]) ^ GMul(M[i][1], tmp[1][j])
                ^ GMul(M[i][2], tmp[2][j]) ^ GMul(M[i][3], tmp[3][j]);
        }
    }

    return 0;
}

// 逆列混合
int invMixColumns(uint8_t(*state)[4]) {
    uint8_t tmp[4][4];
    uint8_t M[4][4] = { {0x0E, 0x0B, 0x0D, 0x09},
                       {0x09, 0x0E, 0x0B, 0x0D},
                       {0x0D, 0x09, 0x0E, 0x0B},
                       {0x0B, 0x0D, 0x09, 0x0E} };  //使用列混合矩阵的逆矩阵

    /* copy state[4][4] to tmp[4][4] */
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            tmp[i][j] = state[i][j];
        }
    }

    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            state[i][j] = GMul(M[i][0], tmp[0][j]) ^ GMul(M[i][1], tmp[1][j])
                ^ GMul(M[i][2], tmp[2][j]) ^ GMul(M[i][3], tmp[3][j]);
        }
    }

    return 0;
}

void debug_uint8(uint8_t(*state_debug)[4],char *tag,int start_debug = 1){        // 用于测试 unsigned __int8 类型的数组 
    printf("%s =>\n",tag);
    for(int i = 0;i<=3;i++){
        for(int j = 0;j<=3;j++){
            printf("0x%x ",state_debug[i][j]);
        }
        printf("\n");
    }
    printf("\n");
    if(start_debug){
        getchar();
    }
}

void debug_uint8_single(uint8_t* arr,char* tag,int start_debug = 1){
    printf("%s =>\n",tag);
    for(int i = 0;i<=15;i++){
        printf("0x%x ",arr[i]);
    }
    printf("\n");
    if(start_debug){
        getchar();
    }
}

// AES-128加密接口,输入key应为16字节长度,输入长度应该是16字节整倍数,
// 这样输出长度与输入长度相同,函数调用外部为输出数据分配内存
int aesEncrypt(const uint8_t* key, uint32_t keyLen, const uint8_t* pt, uint8_t* ct, uint32_t len) {

    AesKey aesKey;
    uint8_t* pos = ct;
    const uint32_t* rk = aesKey.eK;  //解密秘钥指针
    uint8_t out[BLOCKSIZE] = { 0 };
    uint8_t actualKey[16] = { 0 };
    uint8_t state[4][4] = { 0 };

    if (NULL == key || NULL == pt || NULL == ct) {
        printf("param err.\n");
        return -1;
    }

    if (keyLen > 16) {
        printf("keyLen must be 16.\n");
        return -1;
    }

    if (len % BLOCKSIZE) {
        printf("inLen is invalid.\n");
        return -1;
    }

    memcpy(actualKey, key, keyLen);
    keyExpansion(actualKey, 16, &aesKey);  // 秘钥扩展
//    debug_uint8_single(actualKey,"keyExpansion");                ????????????????
    // 使用ECB模式循环加密多个分组长度的数据
    for (int i = 0; i < len; i += BLOCKSIZE) {
        // 把16字节的明文转换为4x4状态矩阵来进行处理
        loadStateArray(state, pt);
//        debug_uint8(state,"loadStateArray");
        // 轮秘钥加
        addRoundKey(state, rk);
//        debug_uint8(state,"addRoundKey");
        for (int j = 1; j < 10; ++j) {
            rk += 4;
            subBytes(state);   // 字节替换
//            debug_uint8(state,"subBytes");
            
            shiftRows(state);  // 行移位
//            debug_uint8(state,"shiftRows");
            
            mixColumns(state); // 列混合
//            debug_uint8(state,"mixColumns");
            
            addRoundKey(state, rk); // 轮秘钥加
//            debug_uint8(state,"addRoundKey");
        }

        subBytes(state);    // 字节替换
//        debug_uint8(state,"subBytes");
        
        shiftRows(state);  // 行移位
        debug_uint8(state,"shiftRows");

            
        // 此处不进行列混合
        addRoundKey(state, rk + 4); // 轮秘钥加
//        debug_uint8(state,"addRoundKey");
        
        // 把4x4状态矩阵转换为uint8_t一维数组输出保存
        storeStateArray(state, pos);
//        debug_uint8(state,"storeStateArray");
        for(int i = 0;i<=15;i++) printf("0x%x ",pos[i]);
        puts("");
        
        pos += BLOCKSIZE;  // 加密数据内存指针移动到下一个分组
        pt += BLOCKSIZE;   // 明文数据指针移动到下一个分组
        rk = aesKey.eK;    // 恢复rk指针到秘钥初始位置
    }
    return 0;
}

// AES128解密, 参数要求同加密
int aesDecrypt(const uint8_t* key, uint32_t keyLen, const uint8_t* ct, uint8_t* pt, uint32_t len) {
    AesKey aesKey;
    uint8_t* pos = pt;
    const uint32_t* rk = aesKey.dK;  //解密秘钥指针
    uint8_t out[BLOCKSIZE] = { 0 };
    uint8_t actualKey[16] = { 0 };
    uint8_t state[4][4] = { 0 };

    if (NULL == key || NULL == ct || NULL == pt) {
        printf("param err.\n");
        return -1;
    }

    if (keyLen > 16) {
        printf("keyLen must be 16.\n");
        return -1;
    }

    if (len % BLOCKSIZE) {
        printf("inLen is invalid.\n");
        return -1;
    }

    memcpy(actualKey, key, keyLen);
    keyExpansion(actualKey, 16, &aesKey);  //秘钥扩展,同加密

    for (int i = 0; i < len; i += BLOCKSIZE) {
        // 把16字节的密文转换为4x4状态矩阵来进行处理
        loadStateArray(state, ct);
        // 轮秘钥加,同加密
        addRoundKey(state, rk);

        for (int j = 1; j < 10; ++j) {
            rk += 4;
            invShiftRows(state);    // 逆行移位
            invSubBytes(state);     // 逆字节替换,这两步顺序可以颠倒
            addRoundKey(state, rk); // 轮秘钥加,同加密
            invMixColumns(state);   // 逆列混合
        }

        invSubBytes(state);   // 逆字节替换
        invShiftRows(state);  // 逆行移位
        // 此处没有逆列混合
        addRoundKey(state, rk + 4);  // 轮秘钥加,同加密

        storeStateArray(state, pos);  // 保存明文数据
        pos += BLOCKSIZE;  // 输出数据内存指针移位分组长度
        ct += BLOCKSIZE;   // 输入数据内存指针移位分组长度
        rk = aesKey.dK;    // 恢复rk指针到秘钥初始位置
    }
    return 0;
}
void printHex(uint8_t* ptr, int len,const char* tag) {
    printf("%s\ndata[%d]: ", tag, len);
    for (int i = 0; i < len; ++i) {
        printf("%.2X ", *ptr++);
    }
    printf("\n");
}

void hex2ch(uint8_t* ptr, int len){
    for(int i = 0;i<len;i++){
        printf("%c",*ptr++);
    }
} 

int main() {

    // case 1
    const uint8_t key[16] = { 0xca,0x9d,0x7f,0x4,0x9,0x90,0x1,0xfa,0xd4,0x6,0x61,0xe9,0x3b,0x77,0x5a };

    
    

    
    // inp1
    uint8_t ct[16] = { 0xdc,0xdc,0xcc,0x66,0x8d,0xf3,0x3c,0x15,0x50,0x5e,0xef,0x16,0x46,0xd9,0xd7,0xdf }; 
    uint8_t plain[16] = { 0 };
    aesDecrypt(key, 16, ct, plain, 16);       // 解密
    hex2ch(plain, 16); // 打印解密后的明文数据
//    
    // inp2

    
    uint8_t inp2[16] ={0};
    uint8_t ct2[16] = {0x50,0x27,0x44,0x77,0x65,0xdc,0xa7,0x39,0x68,0xcb,0x7f,0x7b,0x88,0xdd,0x64,0xf};
    uint8_t plain2[16] = { 0 };
    aesDecrypt(key, 16, ct2, plain2, 16);       // 解密
    for(int i =0;i<=15;i++){
        inp2[i] = (plain2[i]-1) ^ ct[i];
    }
    hex2ch(inp2, 16); //
    return 0;
} 
// https://blog.csdn.net/gq1870554301

4、flag

fa9ad36bd2de1586d944cf7b2935dd91
ps:这题浪费了我好多时间啊,对AES的掌握还是有好多毛病

三、jijiji

这题比较有意思,全篇都是win32逆向的知识,最后轻微的魔改xtea加密收尾,学到了不少win32逆向知识
回顾了一下,大概用到的知识有:
(1)、把可执行文件藏在另一个文件的资源中
(2)、子进程以一种诡异的方式执行可执行文件(好像是进程重影?
(3)、进程断链(任务管理器上找不到子进程)
(4)、魔改xtea
 

1、解题思路

被藏到资源里的可执行文件是不完整的,在程序执行过程中,父进程会对子进程的代码进行补齐,我们就考虑在子进程被补齐的时候,把他dump下来,或者想办法Attach上去

2、解题过程

 
0
在writeFile的时候,lpBuff中存储的是被藏起来的可执行程序的所有数据,我们对子进程的代码进行patch,patch出死循环,方便我们后面Attach
 
0
一直到这里,前面的代码都不用管,只是一些对子进程代码修复的工作罢了,只要我们能成功dump或Attach下来,我们就无需搭理前面的工作
单步后,子进程陷入死循环,我们用ce修改器把子进程dump下来,并用IDA打开后,对循环的位置下断点,再Aattach 陷入死循环的子进程,此时,子进程将被我们IDA,之后的工作就很简单了,只是一个魔改的xtea加密
3、exp
#include <stdio.h>  
#include <stdint.h>  


//void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {  
//    unsigned int i;  
//    uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9;  
//    for (i=0; i < num_rounds; i++) {  
//        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);  
//        sum += delta;  
//        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);  
//    }  
//    v[0]=v0; v[1]=v1;  
//}  


// key = "bomb"
void Moencipher( uint32_t v[2], uint32_t const key[4]) {  
unsigned int num_rounds = 33;
    unsigned int i;  
    uint32_t v0=v[0], v1=v[1], sum=0, delta=0x88408067;  
    for (i=0; i < num_rounds; i++) {  
        v0 += (((v1 * 16) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]) ^ sum;  
        
        v1 += (((v0 * 16) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);  
        sum += delta;  
    }  
    v[0]=v0; v[1]=v1;  
} 

//void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {  
//    unsigned int i;  
//    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;  
//    for (i=0; i < num_rounds; i++) {  
//        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);  
//        sum -= delta;  
//        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);  
//    }  
//    v[0]=v0; v[1]=v1;  
//}  

void conver_to_bytes(uint32_t* v){
    uint32_t v0=v[0], v1=v[1];
    printf("%c",v[0] & 0x000000ff);
    printf("%c",(v[0] & 0x0000ff00) >> 8);
    printf("%c",(v[0] & 0x00ff0000) >> 16);
    printf("%c",(v[0] & 0xff000000) >> 24);
    
    printf("%c",v[1] & 0x000000ff);
    printf("%c",(v[1] & 0x0000ff00) >> 8);
    printf("%c",(v[1] & 0x00ff0000) >> 16);
    printf("%c",(v[1] & 0xff000000) >> 24);
}
void decipher( uint32_t v[2], uint32_t const key[4]) {  
    unsigned int i;  
    unsigned int num_rounds = 33;
    
    uint32_t v0=v[0], v1=v[1], delta=0x88408067, sum=delta*num_rounds;  
    
    for (i=0; i < num_rounds; i++) {  
        sum -= delta; 
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);  
        
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]) ^ sum;  
    }  
    v[0]=v0; v[1]=v1;  
}  
void xTea()
{
    
    
    unsigned int cip[8] = {
    0xADD4F778, 0xA6D7F132, 0x61813290, 0x2D4A40A6, 0x00B05F11, 0xB6D59424, 0x231BBFC6, 0xCD405B31
};
    for(int i = 0;i<=3;i++){
        uint32_t v[2]={cip[i*2],cip[i*2+1]};  
        uint32_t const k[4]={0x62,0x6f,0x6d,0x62};  
        decipher( v, k);  
//        printf("解密后的数据:%x %x\n",v[0],v[1]); 
        conver_to_bytes(v);
    }

}


int main()  
{  
    xTea();
    return 0;  
}  

4、flag

2d326e43eb8fea8837737fc0f50f83f2
BabyAnti和dll_puzzle待补充
ps:
BabyAnti看来俩小时一点思路都没有,我安卓真是太差了,有的师傅40分钟就做出来了,佩服
 
--------------------------------------------------------------| 壮心未与年俱老,死去犹能作鬼雄|--------------------------------------------------------------
posted @ 2023-02-18 23:27  TLSN  阅读(421)  评论(2)    收藏  举报