ez_cythonfrom regadgets import * ans = [4108944556, 3404732701, 1466956825, 788072761, 1482427973, 782926647, 1635740553, 4115935911, 2820454423, 3206473923, 1700989382, 2460803532, 2399057278, 968884411, 1298467094, 1786305447, 3953508515, 2466099443, 4105559714, 779131097, 288224004, 3322844775, 4122289132, 2089726849, 656452727, 3096682206, 2217255962, 680183044, 3394288893, 697481839, 1109578150, 2272036063] def xxtea_sctf2024_shift(z, y, sum, k, p, debug = False): e = (sum.value >> 3) & 3 PE = (p & 2) ^ e Ly = y.value << 3 Ry = y.value >> 4 Lz = z.value << 2 Rz = z.value >> 3 LzRy = Rz ^ Ly LyRz = Ry ^ Lz SY = sum.value ^ y.value K = k[PE].value KZ = K ^ z.value result = (LzRy + LyRz) ^ (KZ + SY) return result key = [0x53, 0x79, 0x43, 0x31] # Syc1 dec = xxtea_decrypt(ans, key, delta=0x9e3779b9, round_base=4, round_addi=60, shift_func=xxtea_sctf2024_shift) print(bytes(dec)) # b'SCTF{w0w_y0U_wE1_kNOw_of_cYtH0N}'BBoxAndroid超绝一键apk混淆捏const char *__fastcall Java_com_example_bbandroid_MainActivity_checkFlag(_JNIEnv *a1, __int64 a2, __int64 a3) { time_t v5; // w22 const char *result; // x0 const char *v7; // x21 unsigned int v8; // w23 signed int v9; // w22 __int64 v10; // x19 __int64 v11; // x20 char *v12; // x22 char v13; // w0 int v14; // w9 signed int v15; // w8 unsigned __int64 v16; // x10 unsigned __int64 v17; // x11 int v18; // w12 int v19; // w13 char flag[256]; // [xsp+8h] [xbp-108h] BYREF __int64 v21; // [xsp+108h] [xbp-8h] v21 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40); v5 = time(0LL); result = (const char *)((__int64 (__fastcall *)(_JNIEnv *, __int64, _QWORD))a1->functions->GetStringUTFChars)( a1, a3, 0LL); if ( result ) { v7 = result; v8 = v5 / 1000000 / 100; strncpy(flag, result, 0xFFu); flag[255] = 0; v9 = __strlen_chk(flag, 0x100u); ((void (__fastcall *)(_JNIEnv *, __int64, const char *))a1->functions->ReleaseStringUTFChars)(a1, a3, v7); srand(v8); if ( v9 >= 4 ) { v10 = 0LL; v11 = (unsigned int)v9 >> 2; do { v12 = &flag[4 * v10]; *v12 ^= rand(); v12[1] ^= rand(); v12[2] ^= rand(); v13 = rand(); v14 = 32; v12[3] ^= v13; v15 = *(_DWORD *)v12; do { if ( v15 >= 0 ) v15 *= 2; else v15 = (2 * v15) ^ 0x85B6874F; --v14; } while ( v14 ); *(_DWORD *)&flag[4 * v10++] = v15; } while ( v10 != v11 ); } if ( flag[0] == '3' ) { v16 = 0LL; do { v17 = v16; if ( v16 == 0x27 ) break; v18 = (unsigned __int8)flag[v16 + 1]; v19 = dword_B14[++v16]; } while ( v18 == v19 ); return (const char *)(v17 > 0x26); } else { return 0LL; } } return result; }Expfrom regadgets import * from z3 import * from copy import deepcopy enc = [0x33, 0xC0, 0xC8, 0xA3, 0xF3, 0xBF, 0x1D, 0x1A, 0x3B, 0x41, 0xB7, 0xC6, 0xF1, 0x5E, 0x86, 0x52, 0x52, 0xCF, 0x6B, 0x1E, 0xC5, 0xF9, 0xCB, 0xBF, 0xED, 0x7B, 0x62, 0xF1, 0xF7, 0x43, 0x48, 0x54, 0xFB, 0x85, 0x4C, 0xD9, 0x35, 0x30, 0xF2, 0x6E] print(bytes(enc)) dw = byte2dword(enc) print(dw) s = Solver() x = [BitVec(f"x{i}", 32) for i in range(len(dw))] y = deepcopy(x) for i in range(len(dw)): for j in range(32): x[i] = If(LShR(x[i], 31) == 1, 2*x[i] ^ 0x85b6874f, 2*x[i]) s.add(x[i] == dw[i]) print(s.check()) m = s.model() r = [] for i in y: r.append(m[i].as_long()) print(r) randv = [0x49308bb9,0x3cb3ad,0xfb4e87f,0x75655103,0x6d505b9f,0x1d20580f, 0xdcf4af1,0x3e381967,0x54bcf579,0x73c09db7,0x501b2039,0x1b8950dd, 0x23e73393,0x2b480a88,0x6818cdae,0x61d009ea,0x44c0c5b0,0x385aff3d, 0x5cfb2a7a,0x587f9c07,0x158172f2,0x4d334c89,0x302b76e5,0x5e17f434, 0x692de923,0x806d155,0x3d2c61d8,0x1d09ef4e,0x7c3d83b7,0x1d7621da, 0x2dc0a3ec,0x456e0f71,0x1db2d588,0x3d758c6c,0x3ad36074,0xb033127,0x5a95e47b,0x48a2ab65,0x493b4a8e,0x2f52d9f5 ] randv = [i & 0xff for i in randv] v1 = bxor(dword2byte(r)[:len(enc)], bytes(randv)[:len(enc)]) v2 = bxor_cycle(v1, b'\x1e').decode() print(decode_b64(v2, "nopqrstDEFGHIJKLhijklUVQRST/WXYZabABCcdefgmuv6789+wxyz012345MNOP")) # b'Y0u_@re_r1ght_r3ver53_is_easy!'其中 randv 是通过hook得到的rand()的结果。中间是一个不安全的CRC。easyMCU我自认为这是一个逆向题目，所以把它放到了Reverse下。首先，使用010Editor，打开mcu.s19，发现它直接自动给我转hex了，我们Ctrl+S保存到文件即可。隔壁队伍使用的是bincopy convert mcu.s19 -o binary out.bin进行的转换，也是一种方法。通过图片中的TriCore，我们可以知道固件是Tri经过翻找，我们找到关键代码 /* WARNING: Globals starting with '_' overlap smaller symbols at the same address */ undefined4 FUN_80000690(void) { byte bVar1; bool bVar2; uint uVar3; undefined4 uVar4; int i; bVar2 = FUN_8000125a(0x6000009c,(undefined *)0x60000004,(short *)0x60000000,_DAT_80003990, iRam80003994); if (bVar2) { AES_ENCRYPT(0x60000004,-0x7fffc65d,0x6000007c,0x20); for (i = 0; i < 0x20; i += 1) { uVar3 = rol((uint)*(byte *)(i + 0x6000007c),3); *(char *)(i + 0x6000007c) = (char)uVar3; bVar1 = bRam6000007c; if (i < 0x1f) { bVar1 = *(byte *)(i + 0x6000007d); } *(byte *)(i + 0x6000007c) = bVar1 ^ *(byte *)(i + 0x6000007c); *(byte *)(i + 0x6000007c) = *(byte *)(i + 0x6000007c) ^ 0xff; } FUN_80001278((int *)0x6000009c,(undefined *)0x6000007c,(short *)0x60000000,_DAT_80003990, iRam80003994); uVar4 = 0; } else { uVar4 = 0xffffffff; } return uVar4; } void AES_ENCRYPT(int param_1,int param_2,int param_3,uint param_4) { uint uVar1; undefined8 auStack_c0 [2]; undefined key [176]; FUN_800002b0(param_2,(int)key); for (uVar1 = 0; uVar1 < param_4; uVar1 += 0x10) { FUN_80003782(auStack_c0,(undefined8 *)(param_1 + uVar1),0x10); aes((int)auStack_c0,(int)key); FUN_80003782((undefined8 *)(param_3 + uVar1),auStack_c0,0x10); } return; } void AES_ENCRYPT(int param_1,int param_2,int param_3,uint param_4) { uint uVar1; undefined8 auStack_c0 [2]; undefined key [176]; FUN_800002b0(param_2,(int)key); for (uVar1 = 0; uVar1 < param_4; uVar1 += 0x10) { FUN_80003782(auStack_c0,(undefined8 *)(param_1 + uVar1),0x10); aes((int)auStack_c0,(int)key); FUN_80003782((undefined8 *)(param_3 + uVar1),auStack_c0,0x10); } return; } 写出EXP。from regadgets import * enc = bytes.fromhex('63 D4 DD 72 B0 8C AE 31 8C 33 03 22 03 1C E4 D3 C3 E3 54 B2 1D EB EB 9D 45 B1 BE 86 CD E9 93 D8') print(len(enc)) key = [ 0x2e, 0x35, 0x7d, 0x6a, 0xed, 0x44, 0xf3, 0x4d, 0xad, 0xb9, 0x11, 0x34, 0x13, 0xea, 0x32, 0x4e ] enc = list(enc) for i in range(len(enc)): enc[31-i] ^= 0xff enc[31-i] ^= enc[(32-i) % 32] enc[31-i] = ror8(enc[31-i], 3) aes = AES(key) dec = aes.decrypt_ecb_block(enc[:16]) + aes.decrypt_ecb_block(enc[16:]) print(dec) # b'SCTF{Wlc_t0_the_wd_oF_IOT_s3cur}'
ez_rustx64dbg开调，搜that's，找到一块spatchEvent(new Event("input")))}const ln=Symbol("_assign"),zi={created(e,{modifiers:{lazy:t,trim:n,number:s}},r){e[ln]=ws(r);const o=s||r.props&&r.props.type==="number";We(e,t?"change":"input",i=>{if(i.target.composing)return;let c=e.value;n&&(c=c.trim()),o&&(c=cn(c)),e[ln](c)}),n&&We(e,"change",()=>{e.value=e.value.trim()}),t||(We(e,"compositionstart",qi),We(e,"compositionend",Cs),We(e,"change",Cs))},mounted(e,{value:t}){e.value=t??""},beforeUpdate(e,{value:t,modifiers:{lazy:n,trim:s,number:r}},o){if(e[ln]=ws(o),e.composing)return;const i=r||e.type==="number"?cn(e.value):e.value,c=t??"";i!==c&&(document.activeElement===e&&e.type!=="range"&&(n||s&&e.value.trim()===c)||(e.value=c))}},Ji=["ctrl","shift","alt","meta"],Yi={stop:e=>e.stopPropagation(),prevent:e=>e.preventDefault(),self:e=>e.target!==e.currentTarget,ctrl:e=>!e.ctrlKey,shift:e=>!e.shiftKey,alt:e=>!e.altKey,meta:e=>!e.metaKey,left:e=>"button"in e&&e.button!==0,middle:e=>"button"in e&&e.button!==1,right:e=>"button"in e&&e.button!==2,exact:(e,t)=>Ji.some(n=>e[`${n}Key`]&&!t.includes(n))},Qi=(e,t)=>{const n=e._withMods||(e._withMods={}),s=t.join(".");return n[s]||(n[s]=(r,...o)=>{for(let i=0;i<t.length;i++){const c=Yi[t[i]];if(c&&c(r,t))return}return e(r,...o)})},Xi=Y({patchProp:Wi},Ii);let Os;function Zi(){return Os||(Os=ri(Xi))}const ki=(...e)=>{const t=Zi().createApp(...e),{mount:n}=t;return t.mount=s=>{const r=tl(s);if(!r)return;const o=t._component;!A(o)&&!o.render&&!o.template&&(o.template=r.innerHTML),r.innerHTML="";const i=n(r,!1,el(r));return r instanceof Element&&(r.removeAttribute("v-cloak"),r.setAttribute("data-v-app","")),i},t};function el(e){if(e instanceof SVGElement)return"svg";if(typeof MathMLElement=="function"&&e instanceof MathMLElement)return"mathml"}function tl(e){return z(e)?document.querySelector(e):e}const nl=ve("button",{type:"submit"},"go!",-1),sl={__name:"Greet",setup(e){const t=ts(""),n=ts("");function s(o,i="secret"){for(var c="",u=i.length,d=0;d<o.length;d++){var h=o.charCodeAt(d),x=i.charCodeAt(d%u),w=h^x;c+=String.fromCharCode(w)}return c}async function r(){if(n.value===""){t.value="Please enter a name.";return}btoa(s(n.value))==="JFYvMVU5QDoNQjomJlBULSQaCihTAFY="?t.value="Great, you got the flag!":t.value="No, that's not my name."}return(o,i)=>(mr(),br(ge,null,[ve("form",{class:"row",onSubmit:Qi(r,["prevent"])},[Mo(ve("input",{id:"greet-input","onUpdate:modelValue":i[0]||(i[0]=c=>n.value=c),placeholder:"Enter a name..."},null,512),zi,n.value),nl],32),ve("p",null,Nr(t.value),1)],64))}},rl=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},Kn=e=>(bo("data-v-bacdabd6"),e=e(),yo(),e),ol={class:"container"},il=Kn(()=>ve("h1",null,"Welcome to L3HCTF!",-1)),ll=Kn(()=>ve("p",null,"Hope you have a good time playing.",-1)),cl=Kn(()=>ve("p",null,"Now please tell me a name.",-1)),fl={__name:"App",setup(e){return(t,n)=>(mr(),br("div",ol,[il,ll,cl,Ae(sl)]))}},ul=rl(fl,"__scopeId","data-v-bacdabd6");ki(ul).mount("#app");分析可知，"JFYvMVU5QDoNQjomJlBULSQaCihTAFY=" == base64_encode(bxor_cycle(input,b'secret'))L3HCTF{W3LC0M3_n0_RU57_AnyM0r3}babycomx64dbg附加，注意到中途主程序会往外写一个com（从资源里面读取）。注意到是babycom.dll，我们直接断输入的字符串，发现进去后是一个xteaxtea参数：key=EA 3E D4 1C 70 CB D7 47 98 5E CA DB 53 0C 39 2Bdelta=0x114514round=32然后经过对比发现是一个标准的。继续往下分析，xtea之后还有一个加密。用了一个Bcrypt的加密，调API就可以解密。#include <iostream> #include <Windows.h> int main() { HCRYPTPROV phProv; HCRYPTHASH phHash; HCRYPTKEY phKey; const BYTE key[] = { 0xEA, 0x3E, 0xD4, 0x1C, 0x70, 0xCB, 0xD7, 0x47, 0x98, 0x5E, 0xCA, 0xDB, 0x53, 0x0C, 0x39, 0x2B }; const BYTE MultiByteStr[] = {0xb, 0xaf, 0x51, 0x21, 0x9c, 0x52, 0x10, 0x89, 0x3f, 0x2c, 0x34, 0x30, 0x87, 0x13, 0xc1, 0x4c, 0xc1, 0x7f, 0x81, 0x6e, 0xba, 0xbd, 0xdf, 0x43, 0x1a, 0xf0, 0xd7, 0xde, 0x8e, 0x66, 0xb9, 0x7c }; DWORD pdwDataLen = 32; if (CryptAcquireContextA(&phProv, 0LL, 0LL, 0x18u, 0xF0000000) && CryptCreateHash(phProv, 32771u, 0LL, 0, &phHash) && CryptHashData(phHash, key, 0x10u, 0) && CryptDeriveKey(phProv, 0x660Eu, phHash, 1u, &phKey)) { CryptDecrypt(phKey, 0LL, 0, 0, (BYTE*)MultiByteStr, &pdwDataLen); } return 0; /* Decrypted 2a b4 c1 74 d6 59 aa 05 73 10 7f 9c 40 49 99 62 3c 84 51 8f 3f 37 ab f1 0e fe 61 96 45 ad 41 6a */ }综上所述from regadgets import * encc = pack_dword(byte2dword(bytes.fromhex(""" 2a b4 c1 74 d6 59 aa 05 73 10 7f 9c 40 49 99 62 3c 84 51 8f 3f 37 ab f1 0e fe 61 96 45 ad 41 6a """))) key = byte2dword(b"\xEA\x3E\xD4\x1C\x70\xCB\xD7\x47\x98\x5E\xCA\xDB\x53\x0C\x39\x2B") r = b'' for i in encc: result = xtea_decrypt(i, key, delta=0x114514, rounds=32) r += dword2byte(list(result)) print(r) # L3HCTF{C0M_Th3C0d3_1s_FuN!!!!!!}丢一个Ctypes版本的（纯python解决）from regadgets import * from ctypes import * lib_advapi32 = windll.LoadLibrary('advapi32.dll') pfunc_CryptAcquireContextA = lib_advapi32.CryptAcquireContextA pfunc_CryptCreateHash = lib_advapi32.CryptCreateHash pfunc_CryptHashData = lib_advapi32.CryptHashData pfunc_CryptDeriveKey = lib_advapi32.CryptDeriveKey pfunc_CryptDecrypt = lib_advapi32.CryptDecrypt phProv = c_uint64(0) phHash = c_uint64(0) phKey = c_uint64(0) pdwDataLen = c_uint32(32) if pfunc_CryptAcquireContextA(pointer(phProv), 0, 0, 0x18, 0xF0000000) == 0: print("failed 0") exit(0) if pfunc_CryptCreateHash(phProv, 32771, 0, 0, pointer(phHash)) == 0: print("failed 1") exit(0) key = b"\xEA\x3E\xD4\x1C\x70\xCB\xD7\x47\x98\x5E\xCA\xDB\x53\x0C\x39\x2B" if pfunc_CryptHashData(phHash, create_string_buffer(key), 0x10, 0) == 0: print("failed 2") exit(0) if pfunc_CryptDeriveKey(phProv, 0x660E, phHash, 1, pointer(phKey)) == 0: print("failed 3") exit(0) correct = b"\x0B\xAF\x51\x21\x9C\x52\x10\x89\x3F\x2C\x34\x30\x87\x13\xC1\x4C\xC1\x7F\x81\x6E\xBA\xBD\xDF\x43\x1A\xF0\xD7\xDE\x8E\x66\xB9\x7C" buf = create_string_buffer(correct) pfunc_CryptDecrypt(phKey, 0, 0, 0, buf, pointer(pdwDataLen)) encc = pack_dword(byte2dword(buf.raw), padding=True) r = b'' for i in encc: result = xtea_decrypt(i, byte2dword(key), delta=0x114514, rounds=32) r += dword2byte(list(result)) print(r) # b'L3HCTF{C0M_Th3C0d3_1s_FuN!!!!!!}\xa0\xbf\xbc\xcf>\xb1\x194'
x64_extensionAES-256 密钥扩增魔改from regadgets import * k = bytes([0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f]) iv = bytes([0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0]) a = AES(k) data = open('flag.txt.enc', 'rb').read() print(a.decrypt_cbc(data, iv)) # b"Hey Sekai CTF Player, I hope you are fine and are enjoying the CTF. Keep going, here is your reward! The flag is SEKAI{Pl34Se_It'5_jUs7_@_wAaaarmUp}\n"SEKAI{Pl34Se_It'5_jUs7_@_wAaaarmUp}
Destination挂上TitanHide，注意到NtSetInformationThread, NtGetContextThread这两个反调试x64dbg断下后在线程开始ret即可。NtSetInformationThread会使当前线程从调试器隐藏，调试器跑飞NtGetContextThread可以获取到当前线程的寄存器状况，用来检测DR寄存器来反硬件断点还有一个反调试是我进入后发现的，主线程卡住，但是线程窗口里面有一个线程一直在Sleep(1);，于是干掉就行了。于是我们就得到了第一个patch的附件，我们以这个附件为基础继续调。注意到我们输入完flag之后给我们来了个int3，导致进入SEH流程，如下图所示。图中框起来的是SEH处理函数，我们进去后，显然是似了。我们观察到，这些花指令由2种构成1.call $+5; add [esp], 5; retn2.jnz addr; jz addr显然第一种可以化简为nop，第二种我们可以化简为jmp addr处理脚本如下from pwn import u32, u8 binfile = open("Destination_patched_2.exe","rb").read() founds = [] # find all junkcode index = 0 while True: index = binfile.find(b'\xE8\x00\x00\x00\x00\x83\x04\x24\x05\xC3',index+1) #! index+1 ! 不然死循环了... if index == -1: break founds.append(index) print(index) binfile = bytearray(binfile) for i in founds: print(binfile[i:i+10]) for j in range(i,i+10): binfile[j] = 0x90 print(binfile[i:i+10]) # find all junkcode index = 0 while True: i = binfile.find(b'\x0f\x84',index+1) index = i if i == -1: break if binfile[index+6:index+8] == b'\x0f\x85' and u32(binfile[index+2:index+6]) - u32(binfile[index+8:index+12]) == 6: binfile[i] = 0x90 binfile[i+1] = 0xe9 binfile[i+7] = 0x66 binfile[i+8] = 0x0f binfile[i+9] = 0x18 binfile[i+10] = 0x20 binfile[i+11] = 0x90 index = 0 while True: i = binfile.find(b'\x74',index+1) index = i if i == -1: break if binfile[i+2] == 0x75 and binfile[i+1] - binfile[i+3] == 2: binfile[i] = 0xeb binfile[i+2] = 0x90 binfile[i+3] = 0x90 binfile[i+4] = 0x90 # replace all matches print(open("Destination_p3.exe","wb").write(binfile))处理完花指令后，我们进入Ghidra，直接当成Func，然后手动处理一点东西，就得到了： void xxtea(void) { uint e; uint sum; uint z; uint i; int round; uint y; round = 50; sum = 0; z = src[0xb]; do { sum += 0xa4b46062; e = sum >> 2 & 3; src[0xb] = z; for (i = 0; i < 11; i += 1) { y = src[i + 1]; z = src[i] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (key[i & 3 ^ e] ^ z)); src[i] = z; } z = src[0xb] + ((z >> 5 ^ src[0] << 2) + (src[0] >> 3 ^ z << 4) ^ (sum ^ src[0]) + (key[i & 3 ^ e] ^ z)); src[0xb] = z; round += -1; } while (round != 0); return; }显然的xxtea。分析完这个后，我们下硬件断点，发现没断下来而且值还被改了，我们回到主函数，找到这个地址有一个jmp farida的反汇编这里有点问题，我们x32dbg看一看，发现是jmp far 0x33:xxxxx这是windows下的天堂之门，0x23就是转32位，0x33就是转64位运行，这个是CS寄存器的值。我们把jmp far的目标地址函数dump下来，放到一个二进制文件，拖入ida，选中64 bit mode，就可以看到真正的源码了。可以注意到，这是一个已经玩烂的不安全CRC，它曾出现在：北邮去年招新赛的五子棋程序逆向、D^3CTF，moectf2024中。提供两种解法，第一种就是z3-Solverfrom z3 import * from copy import deepcopy s = Solver() x = [BitVec(f"x{i}", 32) for i in range(12)] y = deepcopy(x) ans = [0xA790FAD6, 0xE8C8A277, 0xCF0384FA, 0x2E6C7FD7, 0x6D33968B, 0x5B57C227, 0x653CA65E, 0x85C6F1FC, 0xE1F32577, 0xD4D7AE76, 0x3FAF6DC4, 0x0D599D8C] print(len(ans)) for i in range(12): for j in range(32): x[i] = If(LShR(x[i], 31) == 1, 2*x[i] ^ 0x84A6972F, 2*x[i]) s.add(x[i] == ans[i]) print(s.check()) print(s.model()) ''' 12 sat [x1 = 1585230664, x10 = 950802794, x0 = 2656343363, x3 = 2246810078, x7 = 688747158, x11 = 422273590, x9 = 2522199337, x4 = 3061995652, x5 = 3304541857, x6 = 582058634, x8 = 428794995, x2 = 3651684911] '''也是最方便的，下面的解法是按照原理来的：由于由于左移会变偶数，而xor后又会变成奇数，所以有唯一解。我们先获取最低位是否为1，如果是1，说明是奇数，如果为奇数，说明它刚刚走的是最高位是1的那条分支，也说明它异或了立即数，我们直接给它异或回来，然后右移1，由于我们已经确定最高位是1，我们给它补上1即可。如果最低位是0，我们就直接右移1，然后确定最高位是0即可。解密脚本#include <iostream> #include <Windows.h> // n = 12 typedef DWORD uint; void xxtea(uint32_t* src, int n, uint32_t const key[4]) { if (n > 0) /* Coding Part */ { uint e; uint sum; uint z; uint i; int round; uint y; round = 50; sum = 0; z = src[0xb]; do { sum += 0xa4b46062; e = sum >> 2 & 3; src[n - 1] = z; for (i = 0; i < n - 1; i += 1) { y = src[i + 1]; z = src[i] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (key[i & 3 ^ e] ^ z)); src[i] = z; } z = src[n - 1] + ((z >> 5 ^ src[0] << 2) + (src[0] >> 3 ^ z << 4) ^ (sum ^ src[0]) + (key[i & 3 ^ e] ^ z)); src[n - 1] = z; round += -1; } while (round != 0); } else if (n <= 0) { uint32_t y, z, sum; unsigned p, rounds, e; n = -n; rounds = 50; sum = rounds * 0xa4b46062; y = src[0]; do { e = (sum >> 2) & 3; for (p = n - 1; p > 0; p--) { z = src[p - 1]; y = src[p] -= ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (key[p & 3 ^ e] ^ z)); } z = src[n - 1]; y = src[0] -= ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (key[p & 3 ^ e] ^ z)); sum -= 0xa4b46062; } while (--rounds); } } unsigned char a[] = {0xd6, 0xfa, 0x90, 0xa7, 0x77, 0xa2, 0xc8, 0xe8, 0xfa, 0x84, 0x03, 0xcf, 0xd7, 0x7f, 0x6c, 0x2e, 0x8b, 0x96, 0x33, 0x6d, 0x27, 0xc2, 0x57, 0x5b, 0x5e, 0xa6, 0x3c, 0x65, 0xfc, 0xf1, 0xc6, 0x85, 0x77, 0x25, 0xf3, 0xe1, 0x76, 0xae, 0xd7, 0xd4, 0xc4, 0x6d, 0xaf, 0x3f, 0x8c, 0x9d, 0x59, 0x0d}; //unsigned char a[] = "flag{111111111111111111111111111111111111111}"; unsigned char k[] = {0x6b, 0x7a, 0x0e, 0x6b, 0xee, 0x11, 0x30, 0xd1, 0x6d, 0x2c, 0xe1, 0xa7, 0xa6, 0xac, 0x99, 0xc1 }; int main() { for (int i = 0; i < 12; i++) { uint32_t n = *(i + (uint32_t*)a); for (int j = 0; j < 32; j++) { if (n & 1) { n ^= 0x84A6972F; n >>= 1; n |= 0x80000000; } else { n >>= 1; n &= 0x7fffffff; } } *(i + (uint32_t*)a) = n; } xxtea((uint32_t*)a, -12, (uint32_t*)k); xxtea((uint32_t*)a, -12, (uint32_t*)k); std::cout << a; //DubheCTF{82e1e3f8-85fe469f-8499dd48-466a9d60} return 0; }regadgets 版本的xxtea expfrom regadgets import * k = [0x6b, 0x7a, 0x0e, 0x6b, 0xee, 0x11, 0x30, 0xd1, 0x6d, 0x2c, 0xe1, 0xa7, 0xa6, 0xac, 0x99, 0xc1] k4 = byte2dword(k) enc = byte2dword(bytes.fromhex(""" 43 95 54 9e 48 b3 7c 5e 2f 4a a8 d9 de 99 eb 85 84 58 82 b6 a1 4e f7 c4 8a 82 b1 22 96 72 0d 29 73 e4 8e 19 29 b5 55 96 6a 19 ac 38 36 62 2b 19 """)) dec = xxtea_decrypt(enc, k4, delta=0xa4b46062, additional_rounds=40) dec = xxtea_decrypt(dec, k4, delta=0xa4b46062, additional_rounds=40) print(dword2bytes(dec))