首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
IoT安全
发新帖
0
1
[原创]Vehicle Cybersecurity Competition CTF 2025 Writeup
发表于: 2026-5-21 09:30
3818
[原创]Vehicle Cybersecurity Competition CTF 2025 Writeup
Tajang
2026-5-21 09:30
3818
这个比赛名字怎么不统一?之前叫Automotive,是和Vicone合办的,现在叫Vehicle 之类,全称:Global Vehicle Cybersecurity Competition (VCC) 2025 这个赛事是8月22-25和8月29日-9月1日 2024的还没学完,做这个属实不太好,目前 ICV技能树一个都没点完。 今年分了红蓝队两种类型,做了那个签到才能解锁后续题目,这几天是边学边做,但几个地方仍然没有头绪 这里主要参考的yichen大佬,具体知识点我再研究研究 后记:靶场关了,少部分题目迁移到了靶场,也无法复现了,贴一下各家wp: > yichen的wp:<a href="elink@eddK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7q4)9J5k6i4N6W2K9i4S2A6L8W2)9J5k6i4q4I4i4K6u0W2j5$3!0E0i4K6u0r3M7#2)9J5c8X3W2&6z5p5#2T1j5Y4S2j5k6#2y4&6K9p5H3#2N6i4b7$3x3p5E0^5k6#2p5`."><mark class="encrypted">940K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7q4)9J5k6i4N6W2K9i4S2A6L8W2)9J5k6i4q4I4i4K6u0W2j5$3!0E0i4K6u0r3M7#2)9J5c8X3W2&6z5p5#2T1j5Y4S2j5k6#2y4&6K9p5H3#2N6i4b7$3x3p5E0^5k6#2p5`.</mark></a>; > > 第一的wp,他做出了全部题目,不过wp貌似没有全放上来:<a href="elink@ce8K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6A6j5$3q4F1K9r3q4U0K9#2)9J5k6h3&6D9i4K6u0r3j5X3I4G2k6#2)9J5c8X3u0D9L8$3y4C8K9r3q4J5j5X3!0J5i4K6u0V1j5%4c8X3i4K6u0V1x3U0l9J5y4g2)9J5k6s2N6J5K9i4c8W2N6i4m8Q4x3V1j5`."><mark class="encrypted">04cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6A6j5$3q4F1K9r3q4U0K9#2)9J5k6h3&6D9i4K6u0r3j5X3I4G2k6#2)9J5c8X3u0D9L8$3y4C8K9r3q4J5j5X3!0J5i4K6u0V1j5%4c8X3i4K6u0V1x3U0l9J5y4g2)9J5k6s2N6J5K9i4c8W2N6i4m8Q4x3V1j5`.</mark></a>, > > 某选手的password_change_policy wp:<a href="elink@89bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1M7r3q4J5L8X3W2K6K9r3y4Z5k6i4k6Q4x3X3g2Y4K9i4c8Z5N6h3u0Q4x3X3g2A6L8#2)9J5c8Y4m8G2M7%4c8K6i4K6u0r3N6X3y4U0i4K6g2X3x3U0l9J5y4g2)9#2k6Y4m8S2M7%4y4%4L8%4u0V1i4K6g2X3j5$3S2S2L8X3N6W2i4K6g2X3M7r3!0D9K9h3y4&6i4K6u0r3"><mark class="encrypted">7baK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1M7r3q4J5L8X3W2K6K9r3y4Z5k6i4k6Q4x3X3g2Y4K9i4c8Z5N6h3u0Q4x3X3g2A6L8#2)9J5c8Y4m8G2M7%4c8K6i4K6u0r3N6X3y4U0i4K6g2X3x3U0l9J5y4g2)9#2k6Y4m8S2M7%4y4%4L8%4u0V1i4K6g2X3j5$3S2S2L8X3N6W2i4K6g2X3M7r3!0D9K9h3y4&6i4K6u0r3</mark></a> > > 某选手韩语wp:<a href="elink@9daK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6@1j5h3g2K6j5h3#2Q4x3X3g2@1K9i4y4@1L8%4u0&6i4K6u0W2j5$3!0E0i4K6u0r3y4e0p5`."><mark class="encrypted">dd7K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6@1j5h3g2K6j5h3#2Q4x3X3g2@1K9i4y4@1L8%4u0&6i4K6u0W2j5$3!0E0i4K6u0r3y4e0p5`.</mark></a> ## Competition Rules(签到) > To begin this competition and unlock the challenges you must thoroughly read through the <a href="elink@e38K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6$3j5$3y4Q4x3X3g2T1L8r3!0U0K9$3S2S2M7X3u0G2M7W2)9J5k6h3W2G2i4K6u0r3M7Y4g2D9k6i4x3`.">rules</a> to find this flag. > > By submitting this flag you acknowledge agreement to the rules of this competition. > > 要开始本次比赛并解锁挑战,您必须仔细阅读规则以找到此标志。 > > 提交此标志即表示您已同意本比赛的规则。 flag在<a href="elink@042K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6$3j5$3y4Q4x3X3g2T1L8r3!0U0K9$3S2S2M7X3u0G2M7W2)9J5k6h3W2G2i4K6u0r3M7Y4g2D9k6i4x3`.">规则</a>的9.2 Sharing Knowledge While collaboration between players during the competition is prohibited, sharing knowledge and experiences after the event is encouraged. The only exception is the solution to the first challenge: "**i-accept-the-rules**" which should not be shared at any time. ## Blue Team Challenges ### TARA Challenge 这个是白送的,给了一个表格,我还以为要做威胁分析打分,谁知道提交就行,测验到了一定分数就给flag,测验全问AI的 **BHVicOne:rXaARH0%dL** ## Red Team Challenges ### AutoGraph [RAMN] > Participants are provided with signed firmware files and a diagnostic log file from a "caringcaribou" UDS RDBI dump, related to a secret over-the-air (OTA) firmware portal in development for RAMN's ECU B and C. > > This challenge invites you to delve into intricate vehicle communication data and sophisticated security mechanisms. Can you leverage this information to unlock the ability to sign your own firmware files? Success in this endeavor promises to enable you in learning more about firmware authentication. > > **Prompt:** I downloaded a firmware update for RAMN’s ECU B and C from a secret OTA portal in development. Can you help me sign my own firmware files? I have attached a caringcaribou UDS RDBI dump log file, if that is any help. (Note: flag is secret key in decimal format – not hexadecimal. It is NOT the password for the .zip file). > > 参赛者将获得已签名的固件文件以及来自“caringcaribou” UDS RDBI 转储的诊断日志文件,这些文件与 RAMN 的 ECU B 和 C 正在开发中的秘密空中固件(OTA)门户相关。 > > 本挑战要求你深入研究复杂的车辆通信数据和先进的安全机制。你能否利用这些信息解锁签名自有固件文件的能力?成功完成此任务将使你进一步了解固件认证。 > > 提示:我从一个正在开发的秘密 OTA 门户下载了 RAMN 的 ECU B 和 C 的固件更新。你能帮我签名自己的固件文件吗?我已附上一个 caringcaribou UDS RDBI 转储日志文件,或许能有所帮助。(注意:flag 为十进制格式的密钥——不是十六进制。它不是.zip 文件的密码。) 附件是challenge4_RDID_dump.log和challenge_signed_firmware_files.zip 我最初没看出来日志是什么,yichen的wp说是 <a href="elink@2deK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6o6j5i4u0A6L8X3N6o6j5i4u0A6j5X3!0#2i4K6u0r3j5$3q4J5K9h3&6Y4j5$3q4J5K9h3u0G2N6b7`.`.">caringcaribou</a> 暴破DID,然后去看了这个工具,以及问了AI,不得不说,再入门一个新行业的时候,各种原理、概念不懂,通过AI学习真的是事半功倍。 为什么是DID暴破流量? 1. 看请求ID:**`7E3`** 是诊断请求(Tester → ECU),**`7EB`** 是 ECU 回复(ECU → Tester)。这正是典型的 **诊断会话 ID 对**。统计结果也印证了:`7E3` 里有 **8033 条 SF(len>0)**(请求),`7EB` 里有 **8028 条 SF(len>0)** + 一些 FF/CF(应答)。 这就是完整的请求-应答对。 2. 看请求数据域格式(除掉 PCI):`0x22 DID_H DID_L ...` = **ReadDataByIdentifier**。在日志里,7E3 的有效载荷几乎都是 `22 xx xx`,只是 DID 每次都在变。这就是“逐个尝试不同 DID”的特征。 3. 看 ECU 的回应,**大多数 7EB 应答是** `7F 22 31` → 否定应答(服务 0x22,NRC=0x31:Request Out Of Range)。说明这个 DID 不支持。少数会返回 **0x62 DID_H DID_L ...** → 肯定应答,带数据。这种模式正好符合“暴破 DID”:测试仪在循环遍历 DID,ECU不支持的都返回 0x31,支持的才回 0x62。 在VSEC 2024那篇文章说过DID是存储一些信息的段,通过SID=22的协议去读,所以这里暴破DID就是在遍历所有数据。这里要判断PCI,PCI就是数据域的第一个字节,下面PCI高代表PCI的高四位。 - 单帧:PCI高=0,第一个字节的低四位是数据长度,第二个字节是SID+0x40(0x7F代表否定),第三、四个字节是DID。后面长度对应的字节就是数据 - 首帧:PCI高=1,第一个字节的低四位和第二个字节共同组成总长度,第三个字节是SID+0x40,第四、五个字节是请求帧的DID。后面是数据 - 连续帧:PCI高=2,第一个字节的低四位是表示第几个帧,后面都是数据 这里要提取数据,不仅要通过PCI截取不同长度的数据,还要判断长度是否合规,比如有效单帧的帧长度是大于等于3的,第二字节是0x62。如果数据长度是0也要排除掉。 根据前面的分析,其实能确定CAN ID是7EB的是回复了,不过脚本不需要用到CAN ID,因为是通过长度和PCI判断的。 ```python import re file="challenge4_RDID_dump.log" # 解析每行的CAN ID和数据域 def parse_candump_log(line): m=re.match(r".*can0\s+(\w+)#([0-9A-Fa-f]+)", line) if not m: return None, None can_id = int(m.group(1), 16) data = bytes.fromhex(m.group(2)) return can_id, data # 把每个DID的数据都以DID为键名存到字典里 def extract_data(file): # 初始化存放结果和连续帧的字典 result={} multi_frame={} with open(file) as f: for line in f: # 提取每行的CAN ID,数据域 can_id,data=parse_candump_log(line) if data is None or len(data)==0: continue # 提取第一个字节的高4位为PCI pci=data[0] >> 4 if pci == 0: # 提取应用数据长度 length=data[0] & 0x0F # 这里验证的是ISO-TP层长度,如果实际总长小于写的长度,说明CAN帧残缺 if len(data)<1+length: continue # 把ISO-TP层的载荷提取出来,UDS报文就是这个载荷 payload=data[1:length+1] # 有效UDS回复帧,必定包含SID、DID,至少三个字节,少于3个字节,说明ISO-TP层写的长度短了,此帧有误,不管它 # 要求必须是0x22的肯定响应 if len(payload)>=3 and payload[0]==0x62: did=payload[1:3] result[did]=payload[3:] elif pci == 1: # 首帧至少要有 PCI + 长度 + 0x62 + DID,5个字节 # 而且首帧肯定带满数据,长度一定是8,如果总长小于8,说明此帧残缺 if len(data) < 8: continue #传输的数据总长度 total_len=((data[0]&0x0F)<<8)|data[1] # 首帧的UDS响应 payload=data[2:] if len(payload)>=3 and payload[0]==0x62: did = payload[1:3].hex().upper() multi_frame[did]={ "total_len":total_len, "data":payload[3:] } elif pci == 2: #连续帧必须有PCI和1个数据,所以最少2个字节 if len(data) < 2: continue payload = data[1:] for did, mf in multi_frame.items(): # 减3是因为首帧提取的总长度包括了SID,DID的三个字节 if len(mf["data"]) < mf["total_len"] - 3: mf["data"] += payload if len(mf["data"]) >= mf["total_len"] - 3: result[did] = mf["data"] return result for did,value in extract_data(file).items(): try: text = value.decode("ascii") print(f"DID 0x{did}: {text}") except: print(f"DID 0x{did}: {value.hex()}") ``` 我写得比AI好一点,AI居然还求通过连续帧的第一个字节低4位,求连续帧数据长度 运行脚本 可以看到有一个公钥: ```pgp -----BEGIN PUBLIC KEY----- MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEzWvXZ0MMevWSHMMCzdJKOq2uXr1kg45NS1z0w8ZWc0Lr n2qYn0QsXdR3aTXK9kDmPx2fH3wxt9OkhrwHnl+Hsg== -----END PUBLIC KEY----- ``` 还有一个`SECP256k1` zip密码可以暴破出来:password12345678 里面有俩hex文件,俩hex.sig文件,hex文件问了AI才知道是ARM架构的芯片固件,不过这里没什么用处 Qwen-Coder很强:<mark class="encrypted">fadK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6U0K9r3q4@1i4K6u0W2M7i4N6W2L8W2)9J5k6h3q4A6i4K6u0r3M7#2)9J5c8X3t1#2y4K6f1^5z5e0u0V1i4K6u0V1k6o6f1$3x3q4)9J5k6o6b7$3k6e0c8Q4x3X3c8S2x3K6t1&6i4K6u0V1k6r3j5J5j5K6t1%4y4K6x3@1k6X3q4W2i4K6y4r3k6X3g2$3i4K6y4p5x3q4)9J5k6e0m8Q4x3X3f1I4z5e0p5`.</mark> 两个sig文件前面一样,我windows装了xxd,所以能直接看到 ```bash ➜ xxd -p .\ECUB.hex.sig cb8f2f4901e5dc0610a562309a0ba238289edd5a6a819a115ca3b2ac802e 758990b2130178e5aa4501e0da0fa9fa02a82c94f9f137664e43562d040d 68b21262 ➜ xxd -p .\ECUC.hex.sig cb8f2f4901e5dc0610a562309a0ba238289edd5a6a819a115ca3b2ac802e 7589ab711a35e232b03c5baa9ad2d1f3f74d348381ff31203ab3ce66f598 0de2f945 ``` Powershell里用`Format-Hex .\ECUC.hex.sig`也能看 根据前面的`SECP256k1`就可以知道这是ECDSA算法了,学习这个请看:<a href="elink@6cdK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9s2g2S2L8X3I4S2L8W2)9J5k6i4A6Z5K9h3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8U0V1%4z5e0f1K6y4U0b7H3c8f1y4p5f1@1p5`."><mark class="encrypted">5baK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9s2g2S2L8X3I4S2L8W2)9J5k6i4A6Z5K9h3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8U0V1%4z5e0f1K6y4U0b7H3c8f1y4p5f1@1p5`.</mark></a>,ECDSA算法的签名,前一半是R,后一半是S,160-bit q 的情况,每部分是20字节,这题是`SECP256k1`,每个部分32字节。 前32个字节(R)一样就是k一样,可以通过 重复k攻击(nonce重用攻击) 恢复私钥,这个攻击是不需要公钥的,这一题给公钥是为了让我们验证用的。比如用私钥签发一个文件,用公钥验证一下。 需要两个参数 1. **椭圆曲线参数** (secp256k1) 2. **两个消息的哈希值** (z1 和 z2) 这里Qwen3-Coder再次出手,加上我的改造: ```python {title="AutoGraph.py"} #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ ECDSA私钥恢复工具 通过两个使用相同nonce的签名来恢复私钥 无需公钥 """ import hashlib import binascii def main(): # 文件名配置 sig_file1 = "challenge_signed_firmware_files\ECUB.hex.sig" sig_file2 = "challenge_signed_firmware_files\ECUC.hex.sig" msg_file1 = "challenge_signed_firmware_files\ECUB.hex" msg_file2 = "challenge_signed_firmware_files\ECUC.hex" # secp256k1曲线参数 n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 # 阶数 print("=== ECDSA私钥恢复工具 ===") print(f"签名文件1: {sig_file1}") print(f"签名文件2: {sig_file2}") print(f"消息文件1: {msg_file1}") print(f"消息文件2: {msg_file2}") print(f"曲线阶数 n = 0x{n:064x}") print() try: # 读取签名文件 print("=== 读取签名数据 ===") r1, s1 = read_sig_file(sig_file1) r2, s2 = read_sig_file(sig_file2) # 计算消息哈希 print("\n=== 计算消息哈希 ===") z1 = get_file_hash(msg_file1) z2 = get_file_hash(msg_file2) # 恢复私钥 k, private_key = recover_private_key(r1, s1, r2, s2, z1, z2, n) # 输出结果 print("\n=== 最终结果 ===") print(f"使用的Nonce (十六进制): 0x{k:064x}") print(f"使用的Nonce (十进制): {k}") print(f"恢复的私钥 (十六进制): 0x{private_key:064x}") print(f"恢复的私钥 (十进制): {private_key}") except FileNotFoundError as e: print(f"错误: 找不到文件 - {e}") print("请确保以下文件存在:") print(f" - {sig_file1}") print(f" - {sig_file2}") print(f" - {msg_file1}") print(f" - {msg_file2}") except Exception as e: print(f"错误: {e}") def read_sig_file(filename): """读取sig文件并解析ECDSA签名""" try: with open(filename, 'rb') as f: data = f.read() hex_data = data.hex() print(f"文件 {filename} 内容: {hex_data}") except FileNotFoundError: # 如果文件不存在,直接使用文件名作为hex字符串 with open(filename.replace('.sig', ''), 'rb') as f: data = f.read() hex_data = data.hex() # 解析签名数据 if len(hex_data) >= 128: # 至少64字节 # 假设前64字节是r和s r_hex = hex_data[:64] s_hex = hex_data[64:128] r = int(r_hex, 16) s = int(s_hex, 16) print(f" r = 0x{r:064x}") print(f" s = 0x{s:064x}") return r, s else: raise ValueError(f"签名文件 {filename} 数据不足") def get_file_hash(filename): """计算文件的SHA-256哈希值""" with open(filename, 'rb') as f: content = f.read() hash_value = hashlib.sha256(content).digest() hash_int = int.from_bytes(hash_value, 'big') print(f"文件 {filename} SHA256: {hash_int:064x}") return hash_int def recover_private_key(r1, s1, r2, s2, z1, z2, n): """通过两个签名恢复私钥""" print("\n=== 私钥恢复计算 ===") # 检查是否使用了相同的r值(nonce重用) if r1 != r2: print("警告: 两个签名的r值不同,可能不适用nonce重用攻击") print(f"r1 = 0x{r1:064x}") print(f"r2 = 0x{r2:064x}") r = r1 # 使用第一个签名的r值 # 计算 nonce k = (z1 - z2) / (s1 - s2) mod n s_diff = (s1 - s2) % n z_diff = (z1 - z2) % n # 处理负数 if s_diff == 0: raise ValueError("s1 == s2,无法计算,请检查数据") if s_diff < 0: s_diff = (s_diff + n) % n if z_diff < 0: z_diff = (z_diff + n) % n # 计算k k = (z_diff * pow(s_diff, -1, n)) % n print(f"Nonce (k) = 0x{k:064x}") # 计算私钥 d = (s1 * k - z1) / r mod n temp = (s1 * k - z1) % n if temp < 0: temp = (temp + n) % n d = (temp * pow(r, -1, n)) % n print(f"Private key (d) = 0x{d:064x}") # 验证计算 d_verify = ((s2 * k - z2) * pow(r, -1, n)) % n print(f"Verification key = 0x{d_verify:064x}") print(f"Keys match: {d == d_verify}") return k, d if __name__ == "__main__": main() ``` 答案是:`58198666691408413489157977283298548714183388226985257069167369868995344613920` ### Password Change Policy [RAMN] > This challenge dives into Universal Diagnostic Services (UDS) and firmware reverse engineering. You'll need to reconstruct a complete firmware image from a raw CAN log file. > > The main goal is to identify and understand a new Security Access algorithm embedded within the firmware. This algorithm is common to other automotive security access algorithms, requiring meticulous binary analysis to extract. Success hinges on your UDS knowledge and reverse engineering skills. > > ***Prompt:*** I updated my RAMN with a new firmware for ECU C, but it seems like the Security Access algorithm has been updated and I can’t unlock it anymore. > > ECU C just gave me the seed: 9A5ABF0C1CAAFDEB72761E909501D6E9. > > What is the answer to that seed? (Note: flag is 32-character hexadecimal string, all caps). > > 本挑战涉及通用诊断服务(UDS)和固件逆向工程。你需要从原始的 CAN 日志文件中重建完整的固件镜像。 > > 主要目标是识别并理解嵌入在固件中的新型安全访问算法。这种算法与其他汽车安全访问算法类似,需要进行细致的二进制分析才能提取出来。成功与否取决于你对 UDS 的理解以及你的逆向工程技能。 > > 提示:我用 ECU C 的新固件更新了我的 RAMN,但似乎安全访问算法已经更新了,我现在无法解锁它了。 > > ECU C 刚刚给了我一个种子:9A5ABF0C1CAAFDEB72761E909501D6E9。 > > 这个种子的答案是什么?(注意:flag 是一个 32 位字符的十六进制字符串,全部大写)。 给了提示,就是提取固件分析,和安全访问算法 不给提示也能知道大致内容(先射箭再画靶子) 0x36服务是数据传输服务,靠他来传输数据,但是需要请求一下,而请求的SID分两种,请求下载0x34,请求上传0x35 但这里面没有#34或#35的字样,也就是只给了传输帧 固件都很大,都是首帧加连续帧的组合,连续帧没什么好说的,第一个字节代表第几个片段,后面都是数据 首帧不一样,一般是前两个字节是PCI和数据总长度,第三个字节是回应的SID,也就是0x36,第四个字节代表块序号,因为连续帧最多传输,0xFFF个字节,这远远不够一个固件的大小。首帧加相应连续帧构成一个帧块。所以第四个字节表示这是第几个个帧块,传输完一个块就加0x01,然后把对应块按序号连接起来构成最终固件。后面四个字节是有效数据 还有一点,CAN ID是7E2,通常是诊断请求的发送方,如果正则搜索`7E2#1...36..`就能看到有多少个帧块,还能看到最后的数字在逐个增加,那就是帧块序号 脚本让AI给就行,跟之前的大同小异。 得到了一个bin文件,将其拖入IDA 在函数`sub_8006828` 中发现主要代码块,我不知道yichen怎么翻到这个函数的,伪代码如下: ```c int __fastcall sub_8006828(int a1, _BYTE *a2, unsigned __int16 a3, int a4, _WORD *a5) { int result; // r0 int v6; // r3 dword_20032B04 = a4; dword_20032B08 = (int)a5; *a5 = 0; dword_20032B10 = a1; if ( !a3 ) { *a2 = 0; return sub_80042BC(a2, 19); } if ( (unsigned __int8)*a2 <= 0xFu ) return sub_8003A28(a2, a3, a4, a5); v6 = (unsigned __int8)*a2; if ( v6 == 135 ) return sub_8006150(a2, a3); if ( (unsigned __int8)*a2 > 0x87u ) return sub_80042BC(a2, 17); if ( v6 == 133 ) return sub_8006078(a2, a3); if ( (unsigned __int8)*a2 > 0x85u ) return sub_80042BC(a2, 17); if ( (unsigned __int8)*a2 > 0x27u ) { if ( v6 == 62 ) return sub_8005FF4(a2, a3); return sub_80042BC(a2, 17); } if ( (unsigned __int8)*a2 < 0x10u ) return sub_80042BC(a2, 17); switch ( *a2 ) { case 0x10: result = sub_8004428(a2, a3); break; case 0x11: result = sub_8004544(a2, a3); break; case 0x14: result = sub_80045B4(a2, a3); break; case 0x27: result = sub_8004DB8(a2, a3); break; default: return sub_80042BC(a2, 17); } return result; } ``` 题目提到了安全访问算法,而这个安全访问是0x27服务,我建议阅读:<a href="elink@23bK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8X3S2#2K9h3S2#2K9h3N6W2x3o6V1J5i4K6u0r3j5i4u0@1K9h3y4D9k6g2)9J5c8X3c8W2N6r3q4A6L8s2y4Q4x3V1j5I4x3U0j5@1y4U0f1I4y4e0l9`."><mark class="encrypted">d20K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8X3S2#2K9h3S2#2K9h3N6W2x3o6V1J5i4K6u0r3j5i4u0@1K9h3y4D9k6g2)9J5c8X3c8W2N6r3q4A6L8s2y4Q4x3V1j5I4x3U0j5@1y4U0f1I4y4e0l9`.</mark></a> 首先去看`case 0x27`: ```c int __fastcall sub_8004DB8(int a1, unsigned __int16 a2) { int v3; // r3 if ( a2 <= 1u ) return sub_80042BC(a1, 19); v3 = *(_BYTE *)(a1 + 1) & 0x7F; if ( v3 == 1 ) return sub_8004BF4(a1, a2); if ( v3 != 2 ) return sub_80042BC(a1, 18); if ( a2 != 18 ) return sub_80042BC(a1, 19); return sub_8004CD4(a1, a2); } ``` 函数都点一点,`sub_8004CD4` 有一个 16 次的 for 循环,正好对应了种子的字节数: ```c int __fastcall sub_8004CD4(int result) { _BYTE v1[4]; // [sp+Ch] [bp+Ch] BYREF int i; // [sp+10h] [bp+10h] char v3; // [sp+17h] [bp+17h] v1[0] = 103; v1[1] = *(_BYTE *)(result + 1) & 0x7F; if ( (unsigned int)dword_20032B3C > 4 ) return sub_80042BC(result, 54); if ( (unsigned int)(dword_20032B10 - dword_20032B38) <= 9 ) return sub_80042BC(result, 55); if ( byte_20032B40 != 1 ) return sub_80042BC(result, 36); v3 = 1; for ( i = 0; i <= 15; ++i ) { if ( *(unsigned __int8 *)(i + 2 + result) != (unsigned __int8)byte_20032B0C[i + 28] ) v3 = 0; } if ( v3 ) { byte_20032B40 = 2; if ( *(char *)(result + 1) >= 0 ) return sub_8004268(v1, 2); } else { byte_20032B40 = 0; ++dword_20032B3C; dword_20032B38 = dword_20032B10; return sub_80042BC(result, 53); } return result; } ``` 后面不想写了,去看yichen吧 ------ 参考文章: 1. <a href="elink@c65K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9s2g2S2L8X3I4S2L8W2)9J5k6i4A6Z5K9h3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8U0V1%4z5e0f1K6y4U0b7H3">一文读懂ECDSA算法如何保护数据</a>
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
收藏
・
0
点赞
・
1
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
wx_晨梦
感谢你分享这么好的资源!
2026-7-16 11:10
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
Tajang
15
发帖
25
回帖
50
RANK
关注
私信
他的文章
[求助]Pwnable.kr 的 echo2,理解漏洞原理,但是细节总是有问题,求大佬解答。
3129
[原创]整数溢出的处理方式
4026
[原创]Vehicle Cybersecurity Competition CTF 2025 Writeup
3818
[翻译]RAMN 抗干扰汽车微型网络
3809
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部