news 2026/8/24 7:10:53

从二进制到逻辑:逆向工程实战全流程解析与工具链应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从二进制到逻辑:逆向工程实战全流程解析与工具链应用

最近在分析一个可执行程序时,发现网上关于逆向工程(Reverse Engineering)的资料要么过于理论化,要么就是零散的技巧,缺乏一个从拿到二进制文件到完成核心逻辑分析的完整、可复现的实战流程。对于安全研究、漏洞分析或遗留系统维护的开发者来说,如何系统性地对一个可运行的二进制程序(Runnable Binary)进行逆向,提取其算法、数据结构乃至业务逻辑,是一项非常关键的技能。

本文将以一个虚构但典型的场景为例,完整拆解逆向工程的实战步骤。我们将使用一系列主流工具,从静态分析到动态调试,逐步揭示一个ProgramBench程序(假设为一个性能基准测试工具)的内部工作机制。无论你是刚接触逆向的新手,还是想系统化自己分析流程的开发者,都能从本文中找到可操作的代码、命令和排错思路。

1. 逆向工程核心概念与应用场景

在开始实战之前,我们有必要明确逆向工程(Reverse Engineering)在软件领域的定义和目标。简单来说,逆向工程是从一个已编译的、可运行的二进制程序(如.exe,.elf,.dylib)出发,通过分析其机器代码、数据结构和运行行为,来推导出程序的设计思路、实现算法乃至部分源代码的过程。这与我们熟悉的“正向开发”(从需求到代码再到编译)过程恰恰相反。

为什么开发者需要掌握逆向工程?

  1. 安全研究与漏洞挖掘:分析恶意软件(Malware)的行为,或挖掘商业软件、开源组件中的安全漏洞(如缓冲区溢出、逻辑缺陷)。
  2. 软件兼容性与互操作性:在缺乏文档和源代码的情况下,理解遗留系统或闭源软件的协议、文件格式,以便开发与之交互的新系统。
  3. 算法恢复与学习:研究优秀软件(如游戏、编译器)中使用的特定算法或优化技巧。
  4. 数字取证与事件响应:在安全事件中,分析可疑二进制文件以确定其影响范围和攻击意图。
  5. 调试与问题诊断:当程序崩溃且仅有核心转储(Core Dump)或发行版二进制时,逆向是定位问题根源的重要手段。

法律与道德边界: 必须强调,逆向工程必须在合法授权的范围内进行。例如,分析自己拥有版权的软件、进行授权的安全评估、研究已进入公共领域的软件,或是在法律允许的“合理使用”原则下进行互操作性研究。严禁对受版权保护且未授权的软件进行逆向以进行破解、盗版或制作外挂等非法活动。

本文的示例ProgramBench程序是我们自行编写并编译的,仅用于技术演示。

2. 环境准备与工具链说明

工欲善其事,必先利其器。一个高效的逆向工程环境离不开一系列专业工具。以下是我们本次实战将用到的核心工具及其作用,请根据你的操作系统进行安装。

操作系统:Linux (Ubuntu 22.04) / Windows 10+ / macOS。本文命令以 Linux 为例,但工具在各大平台均有对应版本。目标程序:一个用 C 语言编写的简单ProgramBench程序,编译为 64 位 ELF 可执行文件(Linux)或 PE 文件(Windows)。我们将从零开始“黑盒”分析它。

工具链清单

工具类别工具名称主要用途安装参考(Linux)
静态分析file,strings识别文件类型、提取字符串系统自带
objdump,readelf查看节区、符号表、反汇编binutils包 (sudo apt install binutils)
Ghidra/IDA Pro交互式反汇编、反编译、结构分析Ghidra官网 (开源) / IDA (商业)
Radare2/Cutter命令行/图形化逆向框架sudo apt install radare2 cutter
动态分析strace/ltrace跟踪系统调用、库函数调用系统自带 (sudo apt install strace ltrace)
GDB(GNU Debugger)动态调试、控制程序执行流sudo apt install gdb
ltrace跟踪库函数调用sudo apt install ltrace
高级分析Python+pwntools自动化分析、漏洞利用开发pip install pwntools
Capstone/Keystone反汇编/汇编引擎pip install capstone keystone-engine

版本说明: 工具版本迭代较快,本文重点在于演示通用方法和思路。请以你安装的实际版本为准,核心命令和概念通常保持向后兼容。

示例项目结构准备: 首先,我们创建一个简单的ProgramBench程序作为分析目标。请在一个临时目录中执行以下操作:

# 1. 创建源码文件 cat > programbench.c << 'EOF' #include <stdio.h> #include <string.h> #include <stdlib.h> // 一个简单的校验函数 int verify_serial(const char* input) { const char* secret_serial = "PB-2024-REV"; if (strcmp(input, secret_serial) == 0) { return 1; // 验证成功 } return 0; // 验证失败 } // 一个简单的计算函数 int calculate_score(int iterations) { int score = 100; for (int i = 0; i < iterations; i++) { score += (i % 3); } return score; } int main(int argc, char* argv[]) { printf("[ProgramBench] Performance Evaluator v1.0\n"); if (argc != 3) { printf("Usage: %s <serial_key> <iterations>\n", argv[0]); return 1; } // 验证序列号 if (!verify_serial(argv[1])) { printf("[ERROR] Invalid serial key.\n"); return 1; } printf("[INFO] Serial key accepted.\n"); // 解析迭代次数 int iterations = atoi(argv[2]); if (iterations <= 0 || iterations > 10000) { printf("[ERROR] Iterations must be between 1 and 10000.\n"); return 1; } // 计算并输出分数 int final_score = calculate_score(iterations); printf("[RESULT] Final performance score: %d\n", final_score); return 0; } EOF # 2. 编译程序(关闭部分保护机制以便于演示分析) gcc -o programbench programbench.c -no-pie -fno-stack-protector -m64 # 3. 检查生成的文件 file programbench

编译后,你应该得到一个名为programbench的可执行文件。file命令会显示类似programbench: ELF 64-bit LSB executable, x86-64, ...的信息。这就是我们接下来要分析的“黑盒”。

3. 逆向工程核心步骤拆解

逆向工程通常遵循一个由外到内、由静到动的过程。我们将分析流程分为四个阶段,每个阶段使用不同的工具和技术来获取信息。

3.1 第一阶段:文件信息收集与初步探查

在深入分析代码之前,我们需要了解二进制文件的基本属性。

1. 使用file命令确定文件类型和架构

file programbench

输出会告诉你这是 ELF 可执行文件、动态链接、适用于 x86-64 架构,以及是否被剥离(stripped)了符号表。符号表存储了函数和变量名,被剥离后分析难度会增加。

2. 使用strings命令提取所有可打印字符串

strings programbench

这是一个极其重要且快速的步骤。你可能会直接发现硬编码的密钥、错误信息、格式字符串、引用的库函数名等。在我们的示例中,你应该能看到“PB-2024-REV”“Usage:”“[ERROR] Invalid serial key.”等字符串。这立刻给了我们两个线索:存在一个序列号验证逻辑,以及正确的序列号可能是什么。

3. 使用readelfobjdump查看文件结构

readelf -h programbench # 查看ELF头 readelf -S programbench # 查看节区(Sections)头,如 .text(代码), .data(数据), .rodata(只读数据) objdump -t programbench # 查看符号表(如果存在)

通过查看节区,你可以知道代码段(.text)和数据段(.data,.rodata)的位置和大小。符号表则能列出函数和全局变量名(如果未被剥离)。对于我们的示例,由于编译时没有特别处理,你应能看到mainverify_serialcalculate_score等函数名。

3.2 第二阶段:静态反汇编与反编译

这是逆向的核心,目的是将机器码转换回人类可读的汇编指令,进而尝试恢复高级语言结构。

1. 使用objdump进行反汇编

objdump -d -M intel programbench > disassembly.asm

-d表示反汇编代码段,-M intel指定使用 Intel 语法(比 AT&T 语法更易读)。打开disassembly.asm文件,你会看到所有函数的汇编代码。虽然可读性不如高级语言,但通过寻找call(函数调用)、cmp(比较)、jmp/je/jne(跳转)等指令,可以理清程序流程。

2. 使用 Ghidra 进行高级静态分析(推荐): Ghidra 是美国国家安全局(NSA)开源的反编译工具,能直接将汇编代码反编译为近似 C 语言的伪代码,极大提升了分析效率。

  • 启动:运行ghidraRun,新建项目,将programbench文件导入。
  • 分析:双击文件,在代码浏览器中点击“分析”按钮。Ghidra 会自动识别函数、数据类型和交叉引用。
  • 查看反编译代码:在“符号树”窗口找到main函数并双击,右侧反编译窗口会显示类似以下的伪代码:
undefined8 main(int argc,char **argv) { int iVar1; long lVar2; // ... 变量声明 if (argc == 3) { iVar1 = verify_serial(argv[1]); if (iVar1 != 0) { puts("[INFO] Serial key accepted."); lVar2 = atol(argv[2]); if (0 < (int)lVar2 && (int)lVar2 < 0x270f) { // 0x270f = 9999 iVar1 = calculate_score((int)lVar2); printf("[RESULT] Final performance score: %d\n",(ulong)(uint)iVar1); uVar3 = 0; } // ... 错误处理 } // ... 错误处理 } // ... 错误处理 return uVar3; }

通过反编译,我们几乎一眼就看出了程序逻辑:检查参数个数,验证第一个参数(序列号),转换第二个参数为整数并检查范围,最后调用calculate_score计算并输出。我们还可以同样查看verify_serialcalculate_score函数,快速理解其内部逻辑。

3.3 第三阶段:动态分析与调试

静态分析可能无法揭示所有行为,特别是涉及动态内存分配、复杂循环或加解密逻辑时。动态分析让我们在程序运行时观察其状态。

1. 使用strace跟踪系统调用

strace -o trace.log ./programbench PB-2024-REV 100

strace会记录程序执行过程中所有的系统调用(如文件读写、网络通信、内存分配)。查看trace.log,你可以看到程序打开了哪些文件、进行了哪些网络连接等。对于我们的简单程序,主要会看到write(输出到屏幕)和exit_group等调用。

2. 使用ltrace跟踪库函数调用

ltrace -o libtrace.log ./programbench PB-2024-REV 100

ltrace专门跟踪动态库函数的调用。你会看到printfstrcmpatoi等函数的调用顺序和参数,这对于理解程序流程非常有帮助。例如,你会看到strcmp被调用,其参数之一就是我们输入的“PB-2024-REV”

3. 使用 GDB 进行交互式调试: GDB 是功能最强大的动态调试器,可以设置断点、单步执行、查看内存和寄存器。

gdb ./programbench

在 GDB 交互界面中:

# 设置断点在 main 函数 (gdb) break main # 运行程序,并带上参数 (gdb) run PB-2024-REV 100 # 程序会在 main 入口暂停,使用 nexti (next instruction) 或 stepi (step into) 单步执行 (gdb) nexti # 反汇编当前函数 (gdb) disas # 查看字符串参数 argv[1] 的值 (gdb) x/s *(char**)(($rbp-0x20)+8) # 具体地址需根据反汇编代码调整 # 继续执行直到下一个断点或结束 (gdb) continue

通过 GDB,你可以实时观察程序在验证序列号、计算分数时的内存和寄存器变化,验证静态分析的结论。

3.4 第四阶段:高级分析与模式识别

对于更复杂的程序,可能需要结合脚本进行自动化分析或识别特定模式。

使用 Python 和 pwntools 进行自动化pwntools是一个 CTF(Capture The Flag)和漏洞利用开发框架,但其二进制操作功能对逆向也很有用。

#!/usr/bin/env python3 from pwn import * # 加载二进制文件 elf = ELF('./programbench') # 查找字符串 print(f"String 'PB-2024-REV' at address: {hex(elf.search(b'PB-2024-REV').__next__())}") # 查找函数地址(如果符号表存在) if 'verify_serial' in elf.symbols: print(f"Function 'verify_serial' at address: {hex(elf.symbols['verify_serial'])}") # 也可以直接运行程序并交互 # io = process(['./programbench', 'test', '100']) # print(io.recvall().decode())

这个脚本可以快速定位关键字符串和函数的地址,为后续的补丁或深入分析提供入口点。

4. 完整实战案例:逆向破解 ProgramBench 的“序列号”

现在,让我们将上述所有步骤串联起来,完成一个完整的微型“破解”挑战:在不查看源代码的情况下,让programbench程序接受任意序列号并输出结果。

目标:修改二进制文件,绕过verify_serial函数的检查。方法:通过静态分析找到验证逻辑,并通过二进制补丁(Binary Patching)修改关键跳转指令。

步骤 1:定位验证逻辑使用 Ghidra 打开programbench,找到verify_serial函数。反编译结果大致如下:

bool verify_serial(char *input) { return strcmp(input,"PB-2024-REV") == 0; }

在汇编层面,这个函数通常包含一个strcmp调用,后跟一个testcmp指令来比较结果,然后是一个条件跳转指令(如jejne)。

步骤 2:在汇编视图找到关键跳转在 Ghidra 的汇编视图,查看verify_serial函数。你可能会看到类似如下的片段(地址会不同):

0000000000001155 <verify_serial>: 1155: 55 push rbp ... (函数序言) 1169: e8 e2 fe ff ff call 1050 <strcmp@plt> 116e: 85 c0 test eax,eax 1170: 0f 94 c0 sete al ... (函数尾声)

或者,在main函数中调用verify_serial之后:

11e5: e8 6b ff ff ff call 1155 <verify_serial> 11ea: 85 c0 test eax,eax 11ec: 75 1a jne 1208 <main+0x8c> ; 如果验证失败 (eax!=0),跳转到错误处理

关键点在于jne 1208这条指令。如果strcmp结果不为 0(即字符串不相等),则跳转到错误处理流程。我们的目标就是让这个跳转永不发生。

步骤 3:制定补丁方案最简单的补丁是将条件跳转jne(Jump if Not Equal, 操作码75) 改为无条件跳转jmp(操作码EB),但这会跳过成功提示。更优雅的方法是将其改为无条件不跳转,即nop(No Operation,操作码90) 掉这条指令。但jne是 2 字节指令 (75 1a),而nop是 1 字节,直接替换会导致指令错位。通常我们用两个nop(90 90) 来替换75 1a

步骤 4:使用二进制编辑器进行补丁我们可以使用hexeditBless或 Python 进行补丁。

# 首先备份原文件 cp programbench programbench.patched # 使用 Python 进行补丁 python3 -c " import sys with open('programbench.patched', 'r+b') as f: # 找到 main 函数中调用 verify_serial 后 test eax,eax 的地址 # 我们需要先定位。一个简单的方法是搜索字节序列。 # 从 objdump 输出我们知道关键指令在地址 0x11ea (test) 和 0x11ec (jne)。 # 注意:文件中的偏移量(file offset)可能与内存虚拟地址(virtual address)不同。 # 我们需要计算文件偏移。通常 .text 段在文件中的偏移是 0x1000,虚拟地址也是 0x1000左右。 # 假设 .text 段文件偏移为 0x1000,虚拟地址为 0x1000,那么虚拟地址 0x11ec 对应的文件偏移是 0x11ec - 0x1000 + 0x1000 = 0x11ec? 不对。 # 更准确的方法:用 readelf -S programbench 查看 .text 段的 ‘Offset’ (文件偏移) 和 ‘Addr’ (虚拟地址)。 # 假设 Offset=0x1000, Addr=0x1000,那么文件偏移 = 虚拟地址 - 0x1000 + 0x1000 = 虚拟地址。 # 在我们的简单编译中,通常就是这样。所以我们直接修改文件偏移 0x11ec 处的字节。 f.seek(0x11ec) # 将 jne 0x1208 (75 1a) 替换为 nop nop (90 90) f.write(b'\x90\x90') print('Patch applied at file offset 0x11ec') "

注意:上面的地址0x11ec是示例,你必须根据自己objdump -d programbench输出的实际地址进行修改。查找call verify_serial之后的jne指令地址。

步骤 5:验证补丁效果

# 给补丁后的文件执行权限 chmod +x programbench.patched # 使用错误的序列号测试 ./programbench.patched WRONG-KEY 100

如果补丁成功,程序将输出“[INFO] Serial key accepted.”并计算出分数,尽管我们提供了错误的序列号。

5. 常见问题与排查思路

在逆向过程中,你肯定会遇到各种问题。下面是一些典型问题及其解决思路。

问题现象可能原因排查步骤与解决方案
file命令显示stripped二进制文件的符号表被移除。1. 使用stringsobjdump -d寻找入口点(如_start,main)。
2. 在 Ghidra 中,利用“函数识别”算法(如FUN_00123456)进行分析,通过交叉引用和模式识别来重命名函数。
Ghidra 反编译代码混乱1. 分析不充分。
2. 代码经过混淆或加壳。
1. 在 Ghidra 中重新运行分析器(Analysis -> Auto Analyze),并确保所有选项勾选。
2. 检查程序是否加壳(使用upx -l programbench等工具检测)。如加壳,需先脱壳。
GDB 无法打断点或显示No symbol table调试符号缺失(编译时未加-g)。1. 使用break *0x地址在内存地址上设置断点。
2. 通过反汇编(disas)确定函数入口地址。
动态链接库函数调用不清晰ltrace输出过于繁杂。1. 使用ltrace -e strcmp,printf,atoi ./programbench只跟踪特定函数。
2. 结合strace查看系统调用层面。
修改二进制后程序崩溃补丁破坏了指令对齐或修改了错误地址。1. 使用objdump -d对比原文件和补丁文件的差异。
2. 确保只修改了目标指令,且新指令长度与原指令一致(或使用等长的nop填充)。
3. 在 GDB 中单步执行补丁后的程序,观察崩溃点。
无法理解反汇编的循环或分支汇编代码逻辑复杂。1. 在 Ghidra 中查看反编译视图,高级语言结构更清晰。
2. 在 GDB 中给循环条件设置断点,观察寄存器值的变化。
3. 画出简单的控制流图(CFG)帮助理解。

6. 逆向工程最佳实践与工程建议

将逆向工程从临时性的“黑客行为”转变为可重复、可协作的工程实践,需要遵循一些最佳实践。

1. 文档与记录

  • 分析日志:为每个分析目标建立一个文档,记录关键发现,如字符串、函数地址、数据结构、算法逻辑。
  • 注释重命名:在 Ghidra 或 IDA 中,积极对识别出的函数、变量进行重命名和添加注释。例如,将FUN_00112233重命名为decrypt_buffer
  • 版本控制:对补丁文件、分析脚本、笔记使用 Git 进行版本管理。

2. 环境隔离与安全

  • 虚拟机隔离:始终在虚拟机中分析和运行未知的、尤其是可能恶意的二进制文件。
  • 网络隔离:分析期间断开虚拟机网络,防止恶意软件外联或下载额外组件。
  • 使用快照:在进行分析和动态调试前,创建虚拟机快照,便于随时回滚到干净状态。

3. 方法论与流程化

  • 由外而内:始终坚持从文件信息、字符串、导入表等外围信息开始,再深入核心逻辑。
  • 动静结合:静态分析给出蓝图,动态分析验证假设并发现隐藏逻辑。
  • 假设驱动:先根据已有信息形成假设(如“这个函数负责验证密码”),再通过调试去证实或证伪。

4. 代码与自动化

  • 编写分析脚本:使用 Python 配合pwntoolscapstonekeystone等库自动化重复任务,如搜索特定指令模式、批量修改字节。
  • 结构化数据恢复:当识别出数据结构(如链表、树)时,尝试在反编译器中定义对应的结构体(struct),使伪代码更易读。

5. 法律与道德合规

  • 明确授权:只分析你拥有合法权限的软件。这包括自己开发的软件、明确授权可逆向的软件(如某些开源协议允许)、或用于互操作性研究且在法律豁免范围内的软件。
  • 尊重知识产权:逆向工程的目的是学习和研究,而不是窃取知识产权或制作侵权衍生品。
  • 保密义务:如果在工作中分析第三方代码,务必遵守相关的保密协议(NDA)。

7. 总结与进阶学习路线

通过本文对ProgramBench这个简单示例的完整逆向,我们走过了从文件探查、静态反编译、动态调试到二进制补丁的全流程。关键在于建立一套系统的方法论:信息收集 -> 静态分析(掌握全局) -> 动态验证(观察细节) -> 修改验证(达成目标)

本文掌握的关键点

  1. 工具链运用file/strings/objdump用于初步侦查,Ghidra 用于高级静态分析,strace/ltrace/GDB 用于动态分析。
  2. 核心技能:阅读反汇编代码、理解函数调用约定、识别关键跳转指令、进行基础的二进制补丁。
  3. 分析思维:从字符串和导入函数推断程序功能,通过交叉引用定位关键代码,利用动态调试验证静态分析猜想。

下一步可以继续学习

  • 更复杂的反混淆技术:学习识别和应对控制流扁平化、指令虚拟化等代码混淆技术。
  • 系统内部机制:深入理解操作系统加载器(ELF/PE)、动态链接(PLT/GOT)和内存布局(栈、堆、BSS)。
  • 漏洞利用开发:在逆向的基础上,学习如何发现缓冲区溢出、格式化字符串等漏洞,并编写利用代码(Exploit)。
  • 专业领域逆向:如移动端(Android/iOS)应用逆向、嵌入式固件逆向、游戏逆向等,各有其特定的工具链和分析方法。

实际项目中的优先关注点: 在分析真实世界的大型二进制文件时,不要试图一下子理解所有代码。应优先关注:

  • 程序的入口点主循环
  • 网络通信文件处理函数。
  • 字符串解密配置加载逻辑。
  • 许可证检查关键算法函数。

逆向工程是一门需要大量实践和耐心的艺术。最好的学习方法就是找一些有明确挑战目标的 CTF 逆向题目或开源的可执行文件,从简单到复杂,不断地重复“分析-假设-验证”这个过程。随着经验的积累,你看待二进制文件的视角会从一团混乱的字节,逐渐转变为清晰可辨的逻辑结构。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 7:05:59

下载工具战争:网际快车的陨落、迅雷的降维与 BT 的地下江湖

在带宽以 KB 计的年代&#xff0c;"下载"是一门手艺。56K 的猫和 512K 的小水管面前&#xff0c;浏览器自带的下载框弱不禁风&#xff1a;不支持断点续传&#xff0c;挂到 99% 掉一次线&#xff0c;一夜就白等了。于是装机单上永远有专门的一栏留给下载工具&#xff…

作者头像 李华
网站建设 2026/8/24 7:02:37

CIS扫描仪工作原理深度解析:从配置审计到自动化合规实践

当你用CIS扫描仪扫描这些物品会发生什么&#xff1f;这听起来像是一个充满科幻感的实验&#xff0c;但背后其实是一个严肃且实用的技术话题。很多开发者、运维工程师&#xff0c;甚至是对安全感兴趣的爱好者&#xff0c;都听说过CIS&#xff08;互联网安全中心&#xff09;基准…

作者头像 李华
网站建设 2026/8/24 7:01:45

角色扮演AI的智能切换:如何让LLM在沉浸与实用间无缝平衡

1. 项目概述&#xff1a;角色扮演AI的“出戏”时刻最近在折腾大语言模型&#xff08;LLM&#xff09;应用时&#xff0c;一个特别有意思的问题一直在我脑子里打转&#xff1a;我们费尽心思调教出来的角色扮演AI&#xff0c;真的能在该入戏的时候入戏&#xff0c;该出戏的时候出…

作者头像 李华
网站建设 2026/8/24 7:01:22

Java面试突击:7天高效备战策略与核心考点解析

1. 面试突击的本质与误区澄清"一周突击"听起来像是临时抱佛脚&#xff0c;但在Java技术面试领域&#xff0c;这实际上是对已有知识体系的快速激活和查漏补缺。我经历过三次职业跃迁期的面试准备&#xff0c;发现大多数候选人容易陷入两个极端&#xff1a;要么盲目刷题…

作者头像 李华
网站建设 2026/8/24 7:00:09

华为OD面试Python高频考点与优化策略解析

1. 项目背景与核心价值华为OD&#xff08;Outsourcing Dispatch&#xff09;面试作为华为生态体系的重要人才筛选通道&#xff0c;其技术考察具有鲜明的实战导向性。这份Python八股文整理并非传统意义上的"死记硬背"题库&#xff0c;而是对近三年高频出现的算法实现、…

作者头像 李华
网站建设 2026/8/24 6:59:15

字节跳动Agent与RAG大模型面试8大核心真题解析

这次我们来看字节跳动Agent和RAG大模型面试的8道核心真题。如果你正在准备大厂AI岗位面试&#xff0c;特别是字节跳动这类技术驱动型公司的技术面&#xff0c;这篇文章可以直接帮你抓住重点。字节跳动在大模型应用层面一直走在行业前列&#xff0c;其面试题往往反映了实际业务中…

作者头像 李华