Hello everyoneπ―! Today i will tell you the way to solve the Chatbot challenge in CSCV2025
The question:
So at first you will have an file main like this below:



python pyinstxtractor.py main
Output will be:


Now we will use a python decompiler to make main.pyc file to main.py file I will use pylingual, link in here:https://www.pylingual.io/ The file after decompile to .py such like this:
# Decompiled with PyLingual (https://pylingual.io)
# Internal filename: main.py
# Bytecode version: 3.11a7e (3495)
# Source timestamp: 1970-01-01 00:00:00 UTC (0)
import base64
import json
import time
import random
import sys
import os
from ctypes import CDLL, c_char_p, c_int, c_void_p
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
import ctypes
def get_resource_path(name):
if getattr(sys, 'frozen', False):
base = sys._MEIPASS
else: # inserted
base = os.path.dirname(__file__)
return os.path.join(base, name)
def load_native_lib(name):
return CDLL(get_resource_path(name))
if sys.platform == 'win32':
LIBNAME = 'libnative.dll'
else: # inserted
LIBNAME = 'libnative.so'
lib = None
check_integrity = None
decrypt_flag_file = None
free_mem = None
try:
lib = load_native_lib(LIBNAME)
check_integrity = lib.check_integrity
check_integrity.argtypes = [c_char_p]
check_integrity.restype = c_int
decrypt_flag_file = lib.decrypt_flag_file
decrypt_flag_file.argtypes = [c_char_p]
decrypt_flag_file.restype = c_void_p
free_mem = lib.free_mem
free_mem.argtypes = [c_void_p]
free_mem.restype = None
except Exception as e:
print('Warning: native lib not loaded:', e)
lib = None
check_integrity = None
decrypt_flag_file = None
free_mem = None
def run_integrity_or_exit():
if check_integrity:
ok = check_integrity(sys.executable.encode())
if not ok:
print('[!] Integrity failed or debugger detected. Exiting.')
sys.exit(1)
PUB_PEM = b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsJftFGJC6RjAC54aMncA\nfjb2xXeRECiwHuz2wC6QynDd93/7XIrqTObeTpfBCSpOKRLhks6/nzZFTTsYdQCj\n4roXhWo5lFfH0OTL+164VoKnmUkQ9dppzpmV0Kpk5IQhEyuPYzJfFAlafcHdQvUo\nidkqcOPpR7hznJPEuRbPxJod34Bph/u9vePKcQQfe+/l/nn02nbfYWTuGtuEdpHq\nMkktl4WpB50/a5ZqYkW4z0zjFCY5LIPE7mpUNLrZnadBGIaLoVV2lZEBdLt6iLkV\nHXIr+xNA9ysE304T0JJ/DwM1OXb4yVrtawbFLBu9otOC+Gu0Set+8OjfQvJ+tlT/\nzQIDAQAB\n-----END PUBLIC KEY-----'
public_key = None
try:
pub_path = get_resource_path('public.pem')
if os.path.exists(pub_path):
with open(pub_path, 'rb') as f:
public_key = serialization.load_pem_public_key(f.read())
else: # inserted
public_key = serialization.load_pem_public_key(PUB_PEM)
except Exception as e:
print('Failed loading public key:', e)
public_key = None
def b64url_encode(b):
return base64.urlsafe_b64encode(b).rstrip(b'=').decode()
def b64url_decode(s):
s = s | ('=', 4, len(s) - 4) | 4
return base64.urlsafe_b64decode(s.encode())
def verify_token(token):
if not public_key:
return (False, 'no public key')
try:
payload_b64, sig_b64 = token.strip().split('.', 1)
payload = b64url_decode(payload_b64)
sig = b64url_decode(sig_b64)
public_key.verify(sig, payload, padding.PKCS1v15(), hashes.SHA256())
j = json.loads(payload.decode())
if j.get('role')!= 'VIP':
return (False, 'role != VIP')
if j.get('expiry', 0) < int(time.time()):
return (False, 'expired')
else: # inserted
return (True, j)
except Exception as e:
return (False, str(e))
def sample_token_nonvip():
payload = json.dumps({'user': 'guest', 'expiry': int(time.time()) + 3600, 'role': 'USER'}).encode()
return b64url_encode(payload)
def main():
run_integrity_or_exit()
print('=== Bot Chat === \n 1.chat\n 2.showtoken\n 3.upgrade \n 4.quit')
queries = 0
while True:
cmd = input('> ').strip().lower()
if cmd in ['quit', 'exit']:
return
if cmd == 'chat':
if queries < 3:
print(random.choice(['Hi', 'Demo AI', 'Hello!', 'How can I assist you?', 'I am a chatbot', 'What do you want?', 'Tell me more', 'Interesting', 'Go on...', 'SIUUUUUUU', 'I LOVE U', 'HACK TO LEARN NOT LEARN TO HACK']))
queries = queries | 1
else: # inserted
print('Free queries exhausted. Use \'upgrade\'')
else: # inserted
if cmd == 'showtoken':
print('Token current:' + sample_token_nonvip())
else: # inserted
if cmd == 'upgrade':
run_integrity_or_exit()
token = input('Paste token: ').strip()
ok, info = verify_token(token)
if ok:
if decrypt_flag_file is None:
print('Native library not available -> cannot decrypt')
else: # inserted
flag_path = get_resource_path('flag.enc').encode()
res_ptr = decrypt_flag_file(flag_path)
if not res_ptr:
print('Native failed to decrypt or error')
else: # inserted
flag_bytes = ctypes.string_at(res_ptr)
try:
flag = flag_bytes.decode(errors='ignore')
except:
flag = flag_bytes.decode('utf-8', errors='replace')
print('=== VIP VERIFIED ===')
print(flag)
free_mem(res_ptr)
return None
print('Token invalid:', info)
else: # inserted
print('Unknown. Use chat/showtoken/upgrade/quit')
if __name__ == '__main__':
main()
Let analyze this python code:
def get_resource_path(name):
if getattr(sys, 'frozen', False):
base = sys._MEIPASS # PyInstaller-style temp dir
else:
base = os.path.dirname(__file__) # folder containing this .py
return os.path.join(base, name)
That means all external files are searched next to the program
def load_native_lib(name):
return CDLL(get_resource_path(name))
if sys.platform == 'win32':
LIBNAME = 'libnative.dll'
else: # inserted
LIBNAME = 'libnative.so'
lib = None
check_integrity = None
decrypt_flag_file = None
free_mem = None
try:
lib = load_native_lib(LIBNAME)
check_integrity = lib.check_integrity
check_integrity.argtypes = [c_char_p]
check_integrity.restype = c_int
decrypt_flag_file = lib.decrypt_flag_file
decrypt_flag_file.argtypes = [c_char_p]
decrypt_flag_file.restype = c_void_p
free_mem = lib.free_mem
free_mem.argtypes = [c_void_p]
free_mem.restype = None
except Exception as e:
print('Warning: native lib not loaded:', e)
lib = None
check_integrity = None
decrypt_flag_file = None
free_mem = None
This code tries to load a native library (libnative.dll on Windows or libnative.so on Linux) that exports:
check_integrity(char) -> int decrypt_flag_file(char) -> void free_mem(void) -> None
If loading fails, all three become None and the script prints a warning that native lib not loaded.
def run_integrity_or_exit():
if check_integrity:
ok = check_integrity(sys.executable.encode())
if not ok:
print('[!] Integrity failed or debugger detected. Exiting.')
sys.exit(1)
“If” command show us run_integrity_or_exit() calls check_integrity(sys.executable). If it returns 0, the program print “Integrity failed or debugger detected. Exiting” then exits.
PUB_PEM = b'-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsJftFGJC6RjAC54aMncA\nfjb2xXeRECiwHuz2wC6QynDd93/7XIrqTObeTpfBCSpOKRLhks6/nzZFTTsYdQCj\n4roXhWo5lFfH0OTL+164VoKnmUkQ9dppzpmV0Kpk5IQhEyuPYzJfFAlafcHdQvUo\nidkqcOPpR7hznJPEuRbPxJod34Bph/u9vePKcQQfe+/l/nn02nbfYWTuGtuEdpHq\nMkktl4WpB50/a5ZqYkW4z0zjFCY5LIPE7mpUNLrZnadBGIaLoVV2lZEBdLt6iLkV\nHXIr+xNA9ysE304T0JJ/DwM1OXb4yVrtawbFLBu9otOC+Gu0Set+8OjfQvJ+tlT/\nzQIDAQAB\n-----END PUBLIC KEY-----'
public_key = None
try:
pub_path = get_resource_path('public.pem')
if os.path.exists(pub_path):
with open(pub_path, 'rb') as f:
public_key = serialization.load_pem_public_key(f.read())
else: # inserted
public_key = serialization.load_pem_public_key(PUB_PEM)
except Exception as e:
print('Failed loading public key:', e)
public_key = None
It load an RSA public key: If a public.pem is next to the program it will use this file,else it turn back into PUB_PEM. The next explaination will be copied from chatGPT(because i so lazyπ₯±):
The βJWTβ format used here (important!)
This is not a standard 3-part JWT. The code expects exactly two parts:
token = "<payload_b64url>.<signature_b64url>"
+)The signed content is just the raw payload bytes (no header).
+)Signature algorithm: RSA PKCS#1 v1.5 with SHA-256 (public_key.verify(sig, payload, PKCS1v15(), SHA256())).
+)The payload is JSON and must include:
-“role”: “VIP” -“expiry”: <unix_time_in_future>
+)So a valid token = base64url(JSON) + β.β + base64url(RSA_signature_over_raw_payload).
Let go with our main job:Reverse!
nm -D libnative.so | grep -E 'decrypt_flag_file'
The output is:
0000000000001610 T decrypt_flag_file
Let open libnative.so in radare2 Because cannot determine entrypoint, radare2 will use 0x00001220 at first
β$ r2 -w -e bin.cache=true -e bin.relocs.apply=true -A libnative.so
ERROR: Cannot determine entrypoint, using 0x00001220
INFO: Analyze all flags starting with sym. and entry0 (aa)
INFO: Analyze imports (af@@@i)
INFO: Analyze entrypoint (af@ entry0)
INFO: Analyze symbols (af@@@s)
INFO: Analyze all functions arguments/locals (afva@@@F)
INFO: Analyze function calls (aac)
INFO: Analyze len bytes of instructions for references (aar)
INFO: Finding and parsing C++ vtables (avrr)
INFO: Analyzing methods (af @@ method.*)
INFO: Recovering local variables (afva@@@F)
INFO: Type matching analysis for all functions (aaft)
INFO: Propagate noreturn information (aanr)
INFO: Use -AA or aaaa to perform additional experimental analysis
[0x00001220]>
Let see the disassenbly decrypt_flag_file and the pseudo-c of this function
s 0x00001610(point to 0x1610)
af @ 0x00001610(define function)
pdf @ 0x00001610(print disassembly function)
pdc @ 0x00001610(decompile to pseudo-C)
The Output is:
[0x00001220]> s 0x00001610
[0x00001610]> af @ 0x00001610
[0x00001610]> pdf @ 0x00001610
;-- rip:
β 579: sym.decrypt_flag_file (int64_t arg1);
β `- args(rdi) vars(4:sp[0x10..0x54])
β 0x00001610 4157 push r15
β 0x00001612 4156 push r14
β 0x00001614 4155 push r13
β 0x00001616 4154 push r12
β 0x00001618 55 push rbp
β 0x00001619 53 push rbx
β 0x0000161a 4889fb mov rbx, rdi ; arg1
β 0x0000161d 4883ec28 sub rsp, 0x28
β 0x00001621 e8bafcffff call sym.env_checks_ok
β 0x00001626 85c0 test eax, eax
β ββ< 0x00001628 0f84b2010000 je 0x17e0
β β 0x0000162e 48c7442408.. mov qword [var_8h], 0
β β 0x00001637 488d7c2408 lea rdi, [var_8h]
β β 0x0000163c e87ffaffff call fcn.000010c0
β β 0x00001641 4989c4 mov r12, rax
β β 0x00001644 4885c0 test rax, rax
β βββ< 0x00001647 0f8493010000 je 0x17e0
β ββ 0x0000164d 48837c24080f cmp qword [var_8h], 0xf
β ββββ< 0x00001653 0f8677010000 jbe 0x17d0
β βββ 0x00001659 4889df mov rdi, rbx ; const char *filename
β βββ 0x0000165c 488d35c609.. lea rsi, [0x00002029] ; "rb" ; const char *mode
β βββ 0x00001663 e828fbffff call sym.imp.fopen ; file*fopen(const char *filename, const char *mode)
β βββ 0x00001668 4889c3 mov rbx, rax
β βββ 0x0000166b 4885c0 test rax, rax
β βββββ< 0x0000166e 0f845c010000 je 0x17d0
β ββββ 0x00001674 31f6 xor esi, esi ; long offset
β ββββ 0x00001676 ba02000000 mov edx, 2 ; int whence
β ββββ 0x0000167b 4889c7 mov rdi, rax ; FILE *stream
β ββββ 0x0000167e e8edfaffff call sym.imp.fseek ; int fseek(FILE *stream, long offset, int whence)
β ββββ 0x00001683 4889df mov rdi, rbx ; FILE *stream
β ββββ 0x00001686 e8a5f9ffff call sym.imp.ftell ; long ftell(FILE *stream)
β ββββ 0x0000168b 31d2 xor edx, edx ; int whence
β ββββ 0x0000168d 31f6 xor esi, esi ; long offset
β ββββ 0x0000168f 4889df mov rdi, rbx ; FILE *stream
β ββββ 0x00001692 4889c5 mov rbp, rax
β ββββ 0x00001695 e8d6faffff call sym.imp.fseek ; int fseek(FILE *stream, long offset, int whence)
β ββββ 0x0000169a 4883fd10 cmp rbp, 0x10
β ββββββ< 0x0000169e 0f8e64010000 jle 0x1808
β βββββ 0x000016a4 4889ef mov rdi, rbp ; size_t size
β βββββ 0x000016a7 e804fbffff call sym.imp.malloc ; void *malloc(size_t size)
β βββββ 0x000016ac 4989c5 mov r13, rax
β βββββ 0x000016af 4885c0 test rax, rax
β βββββββ< 0x000016b2 0f8450010000 je 0x1808
β ββββββ 0x000016b8 4889d9 mov rcx, rbx ; FILE *stream
β ββββββ 0x000016bb 4889ea mov rdx, rbp ; size_t nmemb
β ββββββ 0x000016be be01000000 mov esi, 1 ; size_t size
β ββββββ 0x000016c3 4889c7 mov rdi, rax ; void *ptr
β ββββββ 0x000016c6 e8f5faffff call sym.imp.fread ; size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
β ββββββ 0x000016cb 4889df mov rdi, rbx ; FILE *stream
β ββββββ 0x000016ce 4d8d7510 lea r14, [r13 + 0x10]
β ββββββ 0x000016d2 448d7df0 lea r15d, [var_10h]
β ββββββ 0x000016d6 e855faffff call sym.imp.fclose ; int fclose(FILE *stream)
β ββββββ 0x000016db f3410f6f4500 movdqu xmm0, xmmword [r13]
β ββββββ 0x000016e1 0f29442410 movaps xmmword [var_sp_10h], xmm0
β ββββββ 0x000016e6 e805faffff call sym.imp.EVP_CIPHER_CTX_new
β ββββββ 0x000016eb 4889c3 mov rbx, rax
β ββββββ 0x000016ee 4885c0 test rax, rax
β ββββββββ< 0x000016f1 0f8459010000 je 0x1850
β βββββββ 0x000016f7 48837c24081f cmp qword [var_8h], 0x1f
β ββββββββ< 0x000016fd 0f86f5000000 jbe 0x17f8
β βββββββ 0x00001703 e8d8f9ffff call sym.imp.EVP_aes_256_cbc
β βββββββ 0x00001708 4889c6 mov rsi, rax
β βββββββ ; CODE XREF from sym.decrypt_flag_file @ 0x1800(x)
β ββββββββ> 0x0000170b 31d2 xor edx, edx
β βββββββ 0x0000170d 4c8d442410 lea r8, [var_sp_10h]
β βββββββ 0x00001712 4c89e1 mov rcx, r12
β βββββββ 0x00001715 4889df mov rdi, rbx
β βββββββ 0x00001718 e833f9ffff call sym.imp.EVP_DecryptInit_ex
β βββββββ 0x0000171d 85c0 test eax, eax
β ββββββββ< 0x0000171f 0f8423010000 je 0x1848
β βββββββ 0x00001725 4863fd movsxd rdi, ebp ; size_t size
β βββββββ 0x00001728 e883faffff call sym.imp.malloc ; void *malloc(size_t size)
β βββββββ 0x0000172d 4889e2 mov rdx, rsp
β βββββββ 0x00001730 4589f8 mov r8d, r15d
β βββββββ 0x00001733 4c89f1 mov rcx, r14
β βββββββ 0x00001736 4889c6 mov rsi, rax
β βββββββ 0x00001739 4889df mov rdi, rbx
β βββββββ 0x0000173c c704240000.. mov dword [rsp], 0
β βββββββ 0x00001743 4889c5 mov rbp, rax
β βββββββ 0x00001746 c744240400.. mov dword [var_4h], 0
β βββββββ 0x0000174e e87df9ffff call sym.imp.EVP_DecryptUpdate
β βββββββ 0x00001753 85c0 test eax, eax
β ββββββββ< 0x00001755 0f84c5000000 je 0x1820
β βββββββ 0x0000175b 48633424 movsxd rsi, dword [rsp]
β βββββββ 0x0000175f 488d542404 lea rdx, [var_4h]
β βββββββ 0x00001764 4889df mov rdi, rbx
β βββββββ 0x00001767 4801ee add rsi, rbp
β βββββββ 0x0000176a e801f9ffff call sym.imp.EVP_DecryptFinal_ex
β βββββββ 0x0000176f 85c0 test eax, eax
β ββββββββ< 0x00001771 0f84a9000000 je 0x1820
β βββββββ 0x00001777 448b7c2404 mov r15d, dword [var_4h]
β βββββββ 0x0000177c 44033c24 add r15d, dword [rsp]
β βββββββ 0x00001780 418d7f01 lea edi, [r15 + 1]
β βββββββ 0x00001784 4863ff movsxd rdi, edi ; size_t size
β βββββββ 0x00001787 e824faffff call sym.imp.malloc ; void *malloc(size_t size)
β βββββββ 0x0000178c 4989c6 mov r14, rax
β βββββββ 0x0000178f 4885c0 test rax, rax
β ββββββββ< 0x00001792 0f8488000000 je 0x1820
β βββββββ 0x00001798 4d63ff movsxd r15, r15d
β βββββββ 0x0000179b 4889ee mov rsi, rbp ; const void *s2
β βββββββ 0x0000179e 4889c7 mov rdi, rax ; void *s1
β βββββββ 0x000017a1 4c89fa mov rdx, r15 ; size_t n
β βββββββ 0x000017a4 e857f9ffff call sym.imp.memcpy ; void *memcpy(void *s1, const void *s2, size_t n)
β βββββββ 0x000017a9 43c6043e00 mov byte [r14 + r15], 0
β βββββββ 0x000017ae 4889df mov rdi, rbx
β βββββββ 0x000017b1 e89af9ffff call sym.imp.EVP_CIPHER_CTX_free
β βββββββ 0x000017b6 4889ef mov rdi, rbp ; void *ptr
β βββββββ 0x000017b9 e8e2f9ffff call sym.imp.free ; void free(void *ptr)
β βββββββ 0x000017be 4c89ef mov rdi, r13 ; void *ptr
β βββββββ 0x000017c1 e8daf9ffff call sym.imp.free ; void free(void *ptr)
β βββββββ 0x000017c6 4c89e7 mov rdi, r12 ; void *ptr
β βββββββ 0x000017c9 e8d2f9ffff call sym.imp.free ; void free(void *ptr)
β ββββββββ< 0x000017ce eb13 jmp 0x17e3
β βββββββ ; CODE XREFS from sym.decrypt_flag_file @ 0x1653(x), 0x166e(x)
β ββββββββ> 0x000017d0 4c89e7 mov rdi, r12 ; void *ptr
β βββ ββ 0x000017d3 e8c8f9ffff call sym.imp.free ; void free(void *ptr)
β βββ ββ 0x000017d8 0f1f840000.. nop dword [rax + rax]
β βββ ββ ; CODE XREFS from sym.decrypt_flag_file @ 0x1628(x), 0x1647(x), 0x1818(x), 0x1840(x), 0x1860(x)
β ββββββββ> 0x000017e0 4531f6 xor r14d, r14d
β βββββ ; CODE XREF from sym.decrypt_flag_file @ 0x17ce(x)
β ββββββββ> 0x000017e3 4883c428 add rsp, 0x28
β βββββ 0x000017e7 4c89f0 mov rax, r14
β βββββ 0x000017ea 5b pop rbx
β βββββ 0x000017eb 5d pop rbp
β βββββ 0x000017ec 415c pop r12
β βββββ 0x000017ee 415d pop r13
β βββββ 0x000017f0 415e pop r14
β βββββ 0x000017f2 415f pop r15
β βββββ 0x000017f4 c3 ret
..
β βββββ ; CODE XREF from sym.decrypt_flag_file @ 0x16fd(x)
β ββββββββ> 0x000017f8 e8b3f8ffff call sym.imp.EVP_aes_128_cbc
β βββββ 0x000017fd 4889c6 mov rsi, rax
β ββββββββ< 0x00001800 e906ffffff jmp 0x170b
..
β βββββ ; CODE XREFS from sym.decrypt_flag_file @ 0x169e(x), 0x16b2(x)
β ββββββββ> 0x00001808 4889df mov rdi, rbx ; FILE *stream
β β ββ 0x0000180b e820f9ffff call sym.imp.fclose ; int fclose(FILE *stream)
β β ββ 0x00001810 4c89e7 mov rdi, r12 ; void *ptr
β β ββ 0x00001813 e888f9ffff call sym.imp.free ; void free(void *ptr)
β ββββββββ< 0x00001818 ebc6 jmp 0x17e0
..
β β ββ ; CODE XREFS from sym.decrypt_flag_file @ 0x1755(x), 0x1771(x), 0x1792(x)
β ββββββββ> 0x00001820 4889df mov rdi, rbx
β β ββ 0x00001823 e828f9ffff call sym.imp.EVP_CIPHER_CTX_free
β β ββ 0x00001828 4c89ef mov rdi, r13 ; void *ptr
β β ββ 0x0000182b e870f9ffff call sym.imp.free ; void free(void *ptr)
β β ββ 0x00001830 4c89e7 mov rdi, r12 ; void *ptr
β β ββ 0x00001833 e868f9ffff call sym.imp.free ; void free(void *ptr)
β β ββ 0x00001838 4889ef mov rdi, rbp ; void *ptr
β β ββ 0x0000183b e860f9ffff call sym.imp.free ; void free(void *ptr)
β β βββββ< 0x00001840 eb9e jmp 0x17e0
..
β β β ; CODE XREF from sym.decrypt_flag_file @ 0x171f(x)
β ββββββββ> 0x00001848 4889df mov rdi, rbx
β β β 0x0000184b e800f9ffff call sym.imp.EVP_CIPHER_CTX_free
β β β ; CODE XREF from sym.decrypt_flag_file @ 0x16f1(x)
β ββββββββ> 0x00001850 4c89ef mov rdi, r13 ; void *ptr
β β 0x00001853 e848f9ffff call sym.imp.free ; void free(void *ptr)
β β 0x00001858 4c89e7 mov rdi, r12 ; void *ptr
β β 0x0000185b e840f9ffff call sym.imp.free ; void free(void *ptr)
β ββββ< 0x00001860 e97bffffff jmp 0x17e0
[0x00001610]> pdc @ 0x00001610
// callconv: rax amd64 (rdi, rsi, rdx, rcx, r8, r9, xmm0, xmm1, xmm2, xmm3, xmm4);
void sym.decrypt_flag_file (int64_t arg1) {
loc_0x00001610:
push (r15)
push (r14)
push (r13)
push (r12)
push (rbp)
push (rbx)
rbx = rdi // arg1
rsp -= 0x28 // (cstr 0x00000020) "@"
sym.env_checks_ok ()
v = eax & eax
if (!v) goto loc_0x17e0 // likely
goto loc_0x0000162e;
loc_0x000017e0:
// CODE XREFS from sym.decrypt_flag_file @ 0x1628(x), 0x1647(x), 0x1818(x), 0x1840(x), 0x1860(x)
r14d = 0
loc_0x000017e3:
// CODE XREF from sym.decrypt_flag_file @ 0x17ce(x)
rsp += 0x28
rax = r14
rbx = pop ()
rbp = pop ()
r12 = pop ()
r13 = pop ()
r14 = pop ()
r15 = pop ()
return
goto loc_0x0000164d;
return rax;
loc_0x0000164d:
v = qword [var_8h] - 0xf
if (((unsigned) v) <= 0) goto 0x17d0 // likely
goto loc_0x00001659;
loc_0x000017d0:
// CODE XREFS from sym.decrypt_flag_file @ 0x1653(x), 0x166e(x)
rdi = r12 // void *ptr
sym.imp.free () // void free(0)
goto loc_0x000017e0
loc_0x00001659: // orphan
rdi = rbx // const char *filename
rsi = rip + 0x9c6 // "rb" // 0x2029 // const char *mode
sym.imp.fopen () // file*fopen(0, "rb")
rbx = rax
v = rax & rax
if (!v)
goto loc_0x000017d0
loc_0x00001674: // orphan
esi = 0 // long offset
edx = 2 // int whence
rdi = rax // FILE *stream
sym.imp.fseek () // int fseek(0, 0, 0x00000000)
rdi = rbx // FILE *stream
sym.imp.ftell () // long ftell(0)
edx = 0 // int whence
esi = 0 // long offset
rdi = rbx // FILE *stream
rbp = rax
sym.imp.fseek () // int fseek(0, 0, 0)
v = rbp - 0x10
if (v <= 0)
goto loc_0x00001808
loc_0x000016a4: // orphan
rdi = rbp // size_t size // rsp
sym.imp.malloc () // void *malloc(0x00000000)
r13 = rax
v = rax & rax
if (!v)
goto loc_0x00001808
loc_0x000016b8: // orphan
rcx = rbx // FILE *stream
rdx = rbp // size_t nmemb // rsp
esi = 1 // size_t size
rdi = rax // void *ptr
sym.imp.fread () // size_t fread(0, 0x00000000, 0x00000000, 0)
rdi = rbx // FILE *stream
r14 = r13 + 0x10
r15d = var_10h
sym.imp.fclose () // int fclose(0)
xmm0 = xmmword [r13]
xmmword [var_sp_10h] = xmm0
sym.imp.EVP_CIPHER_CTX_new ()
rbx = rax
v = rax & rax
if (!v)
goto loc_0x00001850
loc_0x000016f7: // orphan
v = qword [var_8h] - 0x1f
if (((unsigned) v) <= 0)
goto loc_0x000017f8
loc_0x00001703: // orphan
sym.imp.EVP_aes_256_cbc ()
rsi = rax
loc_0x0000170b: // orphan
// CODE XREF from sym.decrypt_flag_file @ 0x1800(x)
edx = 0
r8 = var_sp_10h
rcx = r12
rdi = rbx
sym.imp.EVP_DecryptInit_ex ()
v = eax & eax
if (!v)
goto loc_0x00001848
loc_0x00001725: // orphan
rdi = ebp // size_t size // rsp
sym.imp.malloc () // void *malloc(0x00000000)
rdx = rsp
r8d = r15d
rcx = r14
rsi = rax
rdi = rbx
dword [rsp] = 0
rbp = rax
dword [var_4h] = 0
sym.imp.EVP_DecryptUpdate ()
v = eax & eax
if (!v)
goto loc_0x00001820
loc_0x0000175b: // orphan
rsi = dword [rsp]
rdx = var_4h
rdi = rbx
rsi += rbp // rsp
sym.imp.EVP_DecryptFinal_ex ()
v = eax & eax
if (!v)
goto loc_0x00001820
loc_0x00001777: // orphan
r15d = dword [var_4h]
r15d += dword [rsp]
edi = r15 + 1
rdi = edi // size_t size
sym.imp.malloc () // void *malloc(0x00000000)
r14 = rax
v = rax & rax
if (!v)
goto loc_0x00001820
loc_0x00001798: // orphan
r15 = r15d
rsi = rbp // const void *s2 // rsp
rdi = rax // void *s1
rdx = r15 // size_t n
sym.imp.memcpy () // void *memcpy(0, 0x0000000000000000, 0)
byte [r14 + r15] = 0
rdi = rbx
sym.imp.EVP_CIPHER_CTX_free ()
rdi = rbp // void *ptr // rsp
sym.imp.free () // void free(0x0000000000000000)
rdi = r13 // void *ptr
sym.imp.free () // void free(0)
rdi = r12 // void *ptr
sym.imp.free () // void free(0)
goto loc_0x000017e3
loc_0x000017e3: // orphan
// CODE XREF from sym.decrypt_flag_file @ 0x17ce(x)
rsp += 0x28
rax = r14
rbx = pop ()
rbp = pop ()
r12 = pop ()
r13 = pop ()
r14 = pop ()
r15 = pop ()
return
return rax;
loc_0x000017f8: // orphan
// CODE XREF from sym.decrypt_flag_file @ 0x16fd(x)
sym.imp.EVP_aes_128_cbc ()
rsi = rax
goto loc_0x0000170b
loc_0x00001808: // orphan
// CODE XREFS from sym.decrypt_flag_file @ 0x169e(x), 0x16b2(x)
rdi = rbx // FILE *stream
sym.imp.fclose () // int fclose(0)
rdi = r12 // void *ptr
sym.imp.free () // void free(0)
goto loc_0x000017e0
loc_0x00001820: // orphan
// CODE XREFS from sym.decrypt_flag_file @ 0x1755(x), 0x1771(x), 0x1792(x)
rdi = rbx
sym.imp.EVP_CIPHER_CTX_free ()
rdi = r13 // void *ptr
sym.imp.free () // void free(0)
rdi = r12 // void *ptr
sym.imp.free () // void free(0)
rdi = rbp // void *ptr // rsp
sym.imp.free () // void free(0x0000000000000000)
goto loc_0x000017e0
loc_0x00001848: // orphan
// CODE XREF from sym.decrypt_flag_file @ 0x171f(x)
rdi = rbx
sym.imp.EVP_CIPHER_CTX_free ()
loc_0x00001850: // orphan
// CODE XREF from sym.decrypt_flag_file @ 0x16f1(x)
rdi = r13 // void *ptr
sym.imp.free () // void free(0)
rdi = r12 // void *ptr
sym.imp.free () // void free(0)
goto loc_0x000017e0
}
We have dump all the flow of decrypt_flag_file,let patch env_checks_ok directly to return 1:
cp libnative.so libnative.so.bak(backup)
r2 -w -e bin.relocs.apply=true -q -c 's 0x000015a0; wx b801000000c3' libnative.so(patch)
r2 -e bin.relocs.apply=true -qc 'pd 3 @ 0x000015a0' libnative.so(verify)
The output is:
;-- env_checks_ok:
0x000012e0 b801000000 mov eax, 1
0x000012e5 c3 ret
0x000012e6 0d0000488d or eax, 0x8d480000
Let use this python code i take from chatGPT to bypass the chatbot entirely and call the native decryptor directly.
# bypass_vip_and_dump_flag_diag.py
import os, sys, ctypes
from ctypes import c_char_p, c_void_p, c_int
def get_resource_path(name):
base = getattr(sys, "_MEIPASS", os.path.dirname(__file__))
return os.path.join(base, name)
LIBNAME = "libnative.dll" if sys.platform == "win32" else "libnative.so"
lib_path = os.path.abspath(get_resource_path(LIBNAME))
flag_path = os.path.abspath(get_resource_path("flag.enc"))
exe_path = os.path.abspath(sys.executable)
print("[i] lib path :", lib_path)
print("[i] flag path:", flag_path)
print("[i] exe path :", exe_path)
if not os.path.exists(lib_path):
raise SystemExit("[!] Library not found")
if not os.path.exists(flag_path):
raise SystemExit("[!] flag.enc not found here")
lib = ctypes.CDLL(lib_path)
# prototypes (match the app)
try:
check_integrity = lib.check_integrity
check_integrity.argtypes = [c_char_p]
check_integrity.restype = c_int
except AttributeError:
check_integrity = None
decrypt_flag_file = lib.decrypt_flag_file
decrypt_flag_file.argtypes = [c_char_p]
decrypt_flag_file.restype = c_void_p
free_mem = lib.free_mem
free_mem.argtypes = [c_void_p]
free_mem.restype = None
# 1) Some builds require this call first.
if check_integrity is not None:
try:
ok = check_integrity(exe_path.encode())
print(f"[i] check_integrity({exe_path}) -> {ok}")
# If it *must* pass, ok should be nonzero. If it returns 0, the lib may refuse to decrypt.
except Exception as e:
print("[!] check_integrity raised:", e)
# 2) Use ABSOLUTE path to flag.enc
ptr = decrypt_flag_file(flag_path.encode())
if not ptr:
raise SystemExit("[!] decrypt_flag_file returned NULL (lib refused / error)")
try:
flag_bytes = ctypes.string_at(ptr)
try:
flag = flag_bytes.decode()
except UnicodeDecodeError:
flag = flag_bytes.decode("utf-8", errors="replace")
print("=== VIP VERIFIED ===")
print(flag)
finally:
free_mem(ptr)
The output when we run this python code should be:
ββ$ python3 bypass_vip_and_dump_flag_diag.py
[i] lib path : /home/son/main_extracted/libnative.so
[i] flag path: /home/son/main_extracted/flag.enc
[i] exe path : /usr/bin/python3
[i] check_integrity(/usr/bin/python3) -> 1
=== VIP VERIFIED ===
CSCV2025{reversed_vip*_chatbot_bypassed}
So the flag is CSCV2025{reversed_vip*_chatbot_bypassed}. Thank for reading this post!πππ
