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分钟就做出来了,佩服
 
--------------------------------------------------------------| 壮心未与年俱老,死去犹能作鬼雄|--------------------------------------------------------------

__EOF__

本文作者_TLSN
本文链接https://www.cnblogs.com/lordtianqiyi/articles/17133961.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   TLSN  阅读(406)  评论(2编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示