
近期,CertiK 参加了 Aptos CTF MOVEment 2022比赛。
与所有夺旗(CTF)比赛一样,参赛团队主要面临的挑战就是如何快速理解和总结复杂代码片断语义。
这次,CertiK 团队决定通过 ChatGPT(一个由 OpenAI 训练的大型语言模型)来解决这一问题。
ChatGPT 最近以其强大的信息整合和对话能力惊艳了全球,在自然语言处理上面表现出了惊人的能力。这次的夺旗比赛,也让我们看到了它在理解和解释用各种编程语言编写的代码方面所具备的价值。
本文将为大家分享我们在此次 CTF MOVEment 2022 比赛中运用 ChatGPT 的经验,并讨论在 CTF 比赛中使用这一工具的优势。
ChatGPT 相关基础代码操作

我们可以向ChatGPT提出关于代码的问题,并得到清晰而简洁的答案,这可以帮助我们迅速掌握代码的功能,在 CTF 竞赛中节省宝贵的时间。
例如,当看到用 Move 编写的代码片段时,ChatGPT 能够提供代码的语义摘要,并以简单的自然语言解释代码的作用。当我们在 CTF 比赛中试图快速理解代码时,这可以为我们节省大量的时间和精力。
例①:总结代码的功能
public fun pow(g: u128, x: u128, p: u128): u128 {let ans = 1;g = g % p;while (x !=0) {if((x & 1) == 1) {ans = ((ans % p) * (g % p)) % p;};x = x >> 1;g = (g * g) % p。};ans}
ChatGPT 的回答:该代码定义了一个名为pow的公共函数,该函数接收三个参数:g、x和p。该函数计算g的x次幂(模数p)的模幂运算结果,它通过使用循环重复对g求平方,并在x的最低有效位为1时将其乘以ans来实现,然后返回结果。总的来说,这段代码提供了一种方法来计算g的模块化指数到x次方,模数为p。
我们对使用 ChatGPT 获得的结果印象非常深刻。尽管代码不是特别长,但在 ChatGPT 的帮助下,理解和总结起来要比直接阅读代码快得多。
这说明了 ChatGPT 可以在一定程度上帮助到那些没有太多经验的工程师。通过使用 ChatGPT,他们可以迅速了解代码的概况,理解其目的和结构,这可以节省大量的时间和精力。
ChatGPT 相关进阶代码操作

尽管 MOVE 是一种相对较新的语言,ChatGPT 还是能够提供相应有用的信息。我们决定通过一个稍高级的程序来进一步测试其能力。这里是另一个示例,ChatGPT 可以帮助解释导致运行时失败的极端情况,并帮助我们在代码测试期间进行调试。
例②:查找一个潜在的运行时错误
fun encrypt_string(plaintext : vector<u8>) : vector<u8> {let key : vector<u8> = transaction_context::get_script_hash();let key_len : u64 = vector::length(&key);let ciphertext : vector<u8> = vector::empty<u8>();let i = 0;while ( i < vector::length(&plaintext) ) {vector::push_back(&mut ciphertext, *vector::borrow(&plaintext, i) ^ *vector::borrow(&key, (i % key_len)));i = i + 1;};ciphertext}
ChatGPT 的回答:如果transaction_context::get_script_hash()返回一个空向量,或者在传入明文或密钥时vector::length()返回0,问题中的代码可能无法执行。在这两种情况下,代码中的 while 循环都不会执行,该函数只会返回一个空向量。
虽然 ChatGPT 可能无法确定异常的确切位置,但它仍然可以提供有用的见解和对极端案例和潜在问题的描述。在这种情况下,ChatGPT 可能会提示transaction_context::get_script_hash()函数可能会返回一个空向量,当用于i% key_len这样的操作时可能会导致错误。这些信息对于试图调试代码和了解潜在错误来源的人来说有一定帮助。
例③:处理移动字节码
除了总结代码语义外,我们也很好奇 ChatGPT 是否能理解不同格式的 Move 字节码。经过测试,我们发现当 Move 字节码以文本形式书写时,ChatGPT 能够理解它,然而并不能解释原始的字节码指令并提供关于其含义或行为的信息。
FunctionDefinition {function: FunctionHandleIndex(1),visibility: Private,is_entry: false,acquires_global_resources: [],code: Some(CodeUnit {locals: SignatureIndex(9),code: [Call(11), StLoc(3), ImmBorrowLoc(3), CallGeneric(0), ImmBorrowLoc(3), VecLen(11), StLoc(4), VecPack(11, 0), StLoc(1), LdU64(0), StLoc(2), CopyLoc(2), ImmBorrowLoc(0), VecLen(11), Lt, BrFalse(35), Branch(17), MutBorrowLoc(1), ImmBorrowLoc(0), CopyLoc(2), VecImmBorrow(11), ReadRef, ImmBorrowLoc(3), CopyLoc(2), CopyLoc(4), Mod, VecImmBorrow(11), ReadRef, Xor, VecPushBack(11), MoveLoc(2), LdU64(1), Add, StLoc(2), Branch(11), MoveLoc(1), Ret]})},
ChatGPT 的回答:你提供的代码是一个用 Move 字节码编写的函数定义。该函数是由 FunctionDefinition 块定义的,它指定了该函数的Function句柄、它的可见性(在本例中是Private)、它是否是一个入口点(在本例中是false)、它所获取的全局资源(在本例中没有)以及该函数的代码。
函数的代码本身是一串字节码指令,每条指令都执行一个特定的操作。例如,Call指令调用函数,StLoc指令在局部变量中存储值,ImmBorrowLoc指令不可更改地借用局部变量,等等。
如果不了解代码的使用环境以及各种指令和值的含义,就很难对代码的功能进行详细的解释。然而,通常情况下这段代码似乎定义了一个调用其他函数、操纵局部变量并执行一些算术和逻辑运算的函数。
它还使用了向量操作,如VecLen和VecPushBack,并不可更改地借用局部变量。总的来说,这段代码看起来很复杂,因此需要更多的信息来了解它的确切功能。
ChatGPT 回答的结果在某种程度上是意料之中的。
我们可以理解 ChatGPT 未能提供对代码深刻理解的情况——因为 ChatGPT 是一个语言模型,它目前还没有专业到可以理解 Move 字节码的程度。尽管如此,它仍然可为所提供的程序生成有意义的描述。
局限性

然而,需要注意的是,ChatGPT 有其局限性。它可以理解 Move 源代码的基本内容,并提供其语义的一般解释,但它无法进行详细的逻辑模拟或提供有关代码行为的可靠信息。
换句话说,ChatGPT 可以成为快速理解用 Move 编写的代码的有用工具,但不应该依赖它来完成更高级的任务或对代码行为进行详细分析。
例④:Target Branch 的代码分析失败
public entry fun add(account: &signer, choice: u8, number: u8) acquires Challenge {let res = borrow_global_mut<Challenge>(signer::address_of(account));assert!(number <= 5, 0);if (choice == 1) {res.balance = res.balance + number;} else if (choice == 2) {res.balance = res.balance * number;} else if (choice == 3) {res.balance = res.balance << number;};if (!res.q3 && res.balance < Initialize_balance) {res.q3 = true;}}
ChatGPT 的回答:要调用add函数并将res.q3设置为true,你可以在调用函数时将choice设置为3,将number设置为使res.balance左移数位后小于Initialize_balance的值。
例如,如果res.balance的初始值是 10,你可以调用函数,选择设置为3,数字设置为3,这将使res.balance左移 3 位,结果值为80。由于这个值大于Initialize_balance,而Initialize_balance被设置为10,所以add函数中的 if 条件将为假,res.q3将保持为false。
然而,如果你在调用函数时将choice设置为3,number设置为2,res.balance将被左移 2 位,结果值为40。由于这小于Initialize_balance,add函数中的 if 条件将为真,res.q3将被设置为true。
因此,为了调用该函数并将res.q3设置为真,你可以在调用 add 函数时将choice设置为3,将number设置为一个可使res.balance被number左移后小于Initialize_balance的值。
在这种情况下,ChatGPT 未能给出正确答案,而是试图说明 40 是小于 10 的。
写在最后

这一次通过使用 ChatGPT 来解决 CTF 总体上来说是一次有价值的体验。
ChatGPT 对于用 Move 编写的代码具备理解和总结的能力,这对开发人员很有帮助。
尽管其同样具备一定的局限性,但是我们相信它仍旧可以作为一个有用的工具,以帮助 Move 语言的开发者进行相应操作。

往期长文回顾
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。
