跳转至

2023 12月第5周周报

完成事项⚓︎

  • 安洵杯、NCTF力所能及的复盘
  • Move CTF的基础学习

未完成事项⚓︎

  • d810 deflat工具研究控制流平坦化
  • 你好PE
  • NCTF复盘没搞完

如何解决未完成事项⚓︎

  • 期末考完再努力吧(笑)

下周待做事项⚓︎

  • d810 deflat工具研究控制流平坦化
  • windbg内核调试学习
  • babyre
  • 研究PE_Loader(有空再说吧……)
  • SM4,Blowfish、CRC64算法研究

本周学习的知识分享⚓︎

一、Move CTF入门⚓︎

详细的环境配置教程可以看探姬师傅的教程
从0开始的签到题 - Hello CTF
我想记录一些常用命令,和报错的解决
用于测试的是Move CTF 2024的例题check in

添加与切换试题网络(注意网址中不要有多余的空格,不然会报错):⚓︎

第一次进入:sui client
具体参数参考

Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> sui client

Config file ["/home/tj/.sui/sui_config/client.yaml"] doesn't exist, do you want to connect to a Sui Full node server [y/N]?y
Sui Full node server URL (Defaults to Sui Devnet if not specified) : https://fullnode.devnet.sui.io:443
Environment alias for [https://fullnode.devnet.sui.io:443] : moveCTF2024
Select key scheme to generate keypair (0 for ed25519, 1 for secp256k1, 2: for secp256r1):
0
Generated new keypair for address with scheme "ed25519" [0xcef64a585358ba722e0e1b860f11eb7e05eaf9347162ac6743c15cc0b60dd877]
Secret Recovery Phrase : [absent weird horn travel ghost polar jazz thank innocent funny cancel warfare]
Client for interacting with the Sui network
再次添加/切换网络
Text Only
1
2
3
4
5
sui client new-env --alias <ALIAS> --rpc <RPC-SERVER-URL>
eg.> sui client new-env --alias moveCTF_demo --rpc https://fullnode.devnet.sui.io:443

sui client switch --env <ALIAS>
eg.> sui client switch --env moveCTF_demo
正常运行:
Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
> sui client
Client for interacting with the Sui network

Usage: sui client [OPTIONS] [COMMAND]

Commands:
  active-address         Default address used for commands when none specified
  active-env             Default environment used for commands when none specified
  addresses              Obtain the Addresses managed by the client
  call                   Call Move function
  chain-identifier       Query the chain identifier from the rpc endpoint
  dynamic-field          Query a dynamic field by its address
  envs                   List all Sui environments
  execute-signed-tx      Execute a Signed Transaction. This is useful when the user prefers to sign elsewhere and
                             use this command to execute
  gas                    Obtain all gas objects owned by the address
  merge-coin             Merge two coin objects into one coin
  new-address            Generate new address and keypair with keypair scheme flag {ed25519 | secp256k1 | secp256r1}
                             with optional derivation path, default to m/44'/784'/0'/0'/0' for ed25519 or
                             m/54'/784'/0'/0/0 for secp256k1 or m/74'/784'/0'/0/0 for secp256r1. Word length can be {
                             word12 | word15 | word18 | word21 | word24} default to word12 if not specified
  new-env                Add new Sui environment
  object                 Get object info
  objects                Obtain all objects owned by the address
  pay                    Pay coins to recipients following specified amounts, with input coins. Length of recipients
                             must be the same as that of amounts
  pay-all-sui            Pay all residual SUI coins to the recipient with input coins, after deducting the gas cost.
                             The input coins also include the coin for gas payment, so no extra gas coin is required
  pay-sui                Pay SUI coins to recipients following following specified amounts, with input coins. Length
                             of recipients must be the same as that of amounts. The input coins also include the coin
                             for gas payment, so no extra gas coin is required
  publish                Publish Move modules
  split-coin             Split a coin object into multiple coins
  switch                 Switch active address and network(e.g., devnet, local rpc server)
  tx-block               Get the effects of executing the given transaction block
  transfer               Transfer object
  transfer-sui           Transfer SUI, and pay gas with the same SUI coin object. If amount is specified, only the
                             amount is transferred; otherwise the entire object is transferred
  upgrade                Upgrade Move modules
  verify-bytecode-meter  Run the bytecode verifier on the package
  verify-source          Verify local Move packages against on-chain packages, and optionally their dependencies
  replay-transaction     Replay a given transaction to view transaction effects. Set environment variable
                             MOVE_VM_STEP=1 to debug
  replay-batch           Replay transactions listed in a file
  replay-checkpoint      Replay all transactions in a range of checkpoints
  help                   Print this message or the help of the given subcommand(s)

Options:
      --client.config <CONFIG>  Sets the file storing the state of our user accounts (an empty one will be created if
                                missing)
      --json                    Return command outputs in json format
  -y, --yes
  -h, --help                    Print help

查看目前的网络环境:sui client envs⚓︎

示例:

Text Only
1
2
3
4
5
6
 sui client envs
╭─────────────┬────────────────────────────────────┬────────╮
│ alias       │ url                                │ active │
├─────────────┼────────────────────────────────────┼────────┤
│ moveCTF2024 │ https://fullnode.devnet.sui.io:443 │ *      │
╰─────────────┴────────────────────────────────────┴────────╯

获取钱包地址:sui client addresses⚓︎

示例:

Text Only
1
2
3
4
5
6
7
> sui client addresses
╭───────────────┬──────────────────────────────────────────────────────────────────────────╮
│ activeAddress │  0xcef64a585358ba722e0e1b860f11eb7e05eaf9347162ac6743c15cc0b60dd877      │
│ addresses     │ ╭──────────────────────────────────────────────────────────────────────╮ │
│               │ │  0xcef64a585358ba722e0e1b860f11eb7e05eaf9347162ac6743c15cc0b60dd877  │ │
│               │ ╰──────────────────────────────────────────────────────────────────────╯ │
╰───────────────┴──────────────────────────────────────────────────────────────────────────╯

获取测试币:(我使用的是Windows Powershell进行操作,不能使用curl命令,win下使用Invoke-WebRequest命令代替curl。其他平台的我暂时没有测试,可以参考探姬师傅的教程)⚓︎

Text Only
1
2
3
4
5
6
7
8
9
$body = @{
    FixedAmountRequest = @{
        recipient = '你的钱包地址'
    }
} | ConvertTo-Json

Invoke-WebRequest -Uri 'https://faucet.devnet.sui.io/gas' -Method POST -Body $body -Headers @{
    'Content-Type' = 'application/json'
}
注意钱包地址里不要有空格!!!
(出现Invoke-WebRequest : 基础连接已经关闭: 连接被意外关闭。Invoke-WebRequest : error code: 1015是因为未使用魔法或魔术回路不稳定。)
获取成功界面:
Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
StatusCode        : 201
StatusDescription : Created
Content           : {"transferredGasObjects":[{"amount":10000000000,"id":"0x912044214a205f6963c7b27cc46a6785b9113c429d2
                    a050faae57f8d0087ff80","transferTxDigest":"G22f5qKc1aLFeVfPmE6to9zqZ4bhkAMHS5jDq6dEx8gw"}],"error":
                    nu...
RawContent        : HTTP/1.1 201 Created
                    Connection: keep-alive
                    Access-Control-Allow-Origin: *
                    Vary: origin,access-control-request-method,access-control-request-headers
                    CF-Cache-Status: DYNAMIC
                    Content-Length: 203
                    ...
Forms             : {}
Headers           : {[Connection, keep-alive], [Access-Control-Allow-Origin, *], [Vary, origin,access-control-request-m
                    ethod,access-control-request-headers], [CF-Cache-Status, DYNAMIC]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 203

触发函数⚓︎

语法:

Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
Call Move function

Usage: sui client call [OPTIONS] --package <PACKAGE> --module <MODULE> --function <FUNCTION> --gas-budget <GAS_BUDGET>

Options:
    --package <PACKAGE>             Object ID of the package, which contains the module
    --module <MODULE>               The name of the module in the package
    --function <FUNCTION>           Function name in module
    --type-args <TYPE_ARGS>...      Type arguments to the generic function being called. All must be specified, or the call will fail
    --args <ARGS>...                Simplified ordered args like in the function syntax ObjectIDs, Addresses must be hex strings
    --gas <GAS>                     ID of the gas object for gas payment, in 20 bytes Hex string If not provided, a gas object with at least gas_budget value will be selected
    --gas-budget <GAS_BUDGET>       Gas budget for this call
    --serialize-unsigned-transaction  Instead of executing the transaction, serialize the bcs bytes of the unsigned transaction data (TransactionData) using base64 encoding, and print out
                                        the string
    --serialize-signed-transaction  Instead of executing the transaction, serialize the bcs bytes of the signed transaction data (SenderSignedData) using base64 encoding, and print out the
                                        string
    --json                          Return command outputs in json format
  -h, --help                            Print help
本题中需要触发get_flag函数
屏幕截图 2023-12-29 160920.png
image.png
这里获取到我们的packageId以构建触发函数:
Text Only
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
> sui client call --function get_flag --package 0x01bbc5180d81f2fc4920ad602a6d9c0d447a85219c673eeee2a16a3b9bdf9d3f --module checkin --gas-budget 10000000

[warn] Client/Server api version mismatch, client api version : 1.15.1, server api version : 1.16.0
Transaction Digest: FcB7CsDCsW3mspcTB5nxtpJydbRXcLQRhm7HWdEJVN2f
╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Data                                                                                     │
├──────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Sender: 0xf1a3394e4cfbc855ffcad1774b7505eff2d87659ad135a9fecf2755b1097bb8f                           │
│ Gas Owner: 0xf1a3394e4cfbc855ffcad1774b7505eff2d87659ad135a9fecf2755b1097bb8f                        │
│ Gas Budget: 10000000 MIST                                                                            │
│ Gas Price: 1000 MIST                                                                                 │
│ Gas Payment:                                                                                         │
│  ┌──                                                                                                 │
│  │ ID: 0x144e80386b6bb8c5e2fe31fdf5299290e7b456c5782a1d11d98cd29e22e08acf                            │
│  │ Version: 110                                                                                      │
│  │ Digest: 7yra2w3ssVADaFrX3FzG9nsZ6b4XQfPPdz9T8ULJkUsV                                              │
│  └──                                                                                                 │
│                                                                                                      │
│ Transaction Kind : Programmable                                                                      │
│ Inputs: []                                                                                           │
│ Commands: [                                                                                          │
│   MoveCall(0x01bbc5180d81f2fc4920ad602a6d9c0d447a85219c673eeee2a16a3b9bdf9d3f::checkin::get_flag()), │
│ ]                                                                                                    │
│                                                                                                      │
│                                                                                                      │
│ Signatures:                                                                                          │
│    UysHNP76g5F0y3kGcje256HLSO9uZsxTXY9JmmLPml06KzvAg7dYj46ongZAbdMn1ZlT+CByx02TE3bniIHCDg==          │
│                                                                                                      │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Effects                                                                               │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Digest: FcB7CsDCsW3mspcTB5nxtpJydbRXcLQRhm7HWdEJVN2f                                              │
│ Status: Success                                                                                   │
│ Executed Epoch: 2517                                                                              │
│                                                                                                   │
│ Mutated Objects:                                                                                  │
│  ┌──                                                                                              │
│  │ ID: 0x144e80386b6bb8c5e2fe31fdf5299290e7b456c5782a1d11d98cd29e22e08acf                         │
│  │ Owner: Account Address ( 0xf1a3394e4cfbc855ffcad1774b7505eff2d87659ad135a9fecf2755b1097bb8f )  │
│  │ Version: 111                                                                                   │
│  │ Digest: 6VR24FpTNg9eqYW8TuxiKQmeNENczLK91m8b3iV1sz5t                                           │
│  └──                                                                                              │
│                                                                                                   │
│ Gas Object:                                                                                       │
│  ┌──                                                                                              │
│  │ ID: 0x144e80386b6bb8c5e2fe31fdf5299290e7b456c5782a1d11d98cd29e22e08acf                         │
│  │ Owner: Account Address ( 0xf1a3394e4cfbc855ffcad1774b7505eff2d87659ad135a9fecf2755b1097bb8f )  │
│  │ Version: 111                                                                                   │
│  │ Digest: 6VR24FpTNg9eqYW8TuxiKQmeNENczLK91m8b3iV1sz5t                                           │
│  └──                                                                                              │
│                                                                                                   │
│ Gas Cost Summary:                                                                                 │
│    Storage Cost: 988000                                                                           │
│    Computation Cost: 1000000                                                                      │
│    Storage Rebate: 978120                                                                         │
│    Non-refundable Storage Fee: 9880                                                               │
│                                                                                                   │
│ Transaction Dependencies:                                                                         │
│    95186xqFzKTmDhUXWw5oxJw2Z4pxqdB6cPDA6aFidRPE                                                   │
│    AyE5rTMnhY4CmfDomoE5vh4TwWGhxdHcJdUPjtyTPE7x                                                   │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
╭────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Block Events                                                                       │
├────────────────────────────────────────────────────────────────────────────────────────────────┤
│  ┌──                                                                                           │
│  │ EventID: FcB7CsDCsW3mspcTB5nxtpJydbRXcLQRhm7HWdEJVN2f:0                                     │
│  │ PackageID: 0x01bbc5180d81f2fc4920ad602a6d9c0d447a85219c673eeee2a16a3b9bdf9d3f               │
│  │ Transaction Module: checkin                                                                 │
│  │ Sender: 0xf1a3394e4cfbc855ffcad1774b7505eff2d87659ad135a9fecf2755b1097bb8f                  │
│  │ EventType: 0x1bbc5180d81f2fc4920ad602a6d9c0d447a85219c673eeee2a16a3b9bdf9d3f::checkin::Flag │
│  │ ParsedJSON:                                                                                 │
│  │   ┌──────┬────────────────────────────────────────────────────────────────────┐             │
│  │   │ flag │ true                                                               │             │
│  │   ├──────┼────────────────────────────────────────────────────────────────────┤             │
│  │   │ user │ 0xf1a3394e4cfbc855ffcad1774b7505eff2d87659ad135a9fecf2755b1097bb8f │             │
│  │   └──────┴────────────────────────────────────────────────────────────────────┘             │
│  └──                                                                                           │
╰────────────────────────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes                                                                                   │
├──────────────────────────────────────────────────────────────────────────────────────────────────┤
│                                                                                                  │
│ Mutated Objects:                                                                                 │
│  ┌──                                                                                             │
│  │ ObjectID: 0x144e80386b6bb8c5e2fe31fdf5299290e7b456c5782a1d11d98cd29e22e08acf                  │
│  │ Sender: 0xf1a3394e4cfbc855ffcad1774b7505eff2d87659ad135a9fecf2755b1097bb8f                    │
│  │ Owner: Account Address ( 0xf1a3394e4cfbc855ffcad1774b7505eff2d87659ad135a9fecf2755b1097bb8f ) │
│  │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI>                                                    │
│  │ Version: 111                                                                                  │
│  │ Digest: 6VR24FpTNg9eqYW8TuxiKQmeNENczLK91m8b3iV1sz5t                                          │
│  └──                                                                                             │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Balance Changes                                                                                   │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│  ┌──                                                                                              │
│  │ Owner: Account Address ( 0xf1a3394e4cfbc855ffcad1774b7505eff2d87659ad135a9fecf2755b1097bb8f )  │
│  │ CoinType: 0x2::sui::SUI                                                                        │
│  │ Amount: -1009880                                                                               │
│  └──                                                                                              │
│                                                                                                   │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
我们的目标数据就是 Transaction Digest: FcB7CsDCsW3mspcTB5nxtpJydbRXcLQRhm7HWdEJVN2f(示例)
将冒号后的数据输入到题目Transaction后,可获得flag

查看当前地址:sui client active-address⚓︎

列出当前地址拥有对象的摘要信息:sui client objects⚓︎

image.png

列出您提供的ID的对象信息:sui client object <OBJECT-ID>⚓︎

image.png

Kali Linux测试(kali兼容性不太好……)⚓︎

我采用二进制自动化构建失败,因此采取了docker安装的方式

  • 启动sui:docker exec -it suidevcontainer bash
  • 获取测试币:~~(失败)~~
  • curl --location --request POST '[https://faucet.devnet.sui.io/gas](https://faucet.devnet.sui.io/gas)' --header 'Content-Type: application/json' --data-raw '{ "FixedAmountRequest": { "recipient": "0x59903bc827e6a93e3d4c2f52e0707bca056076e82978993f8d56ad87e912b593" } }'

二、安洵杯复现⚓︎

mobilego⚓︎

  • 需要安装frida和objection插件进行调试(做题五分钟,装环境两小时[○・`Д´・ ○])

jadx分析:用关键字符串搜索找到主函数(用apk做测试用错误的提示字符串搜索更加容易想到)image.png
image.png
大概是取了R.string.cmp中的数据,经过checkflag函数加密了
在资源文件中寻找image.png
得到了疑似flag的数据 49021}5f919038b440139g74b7Dc88330e5d{6 应该是只是经过了顺序颠倒(但愿吧)
用frida下的objection在雷电模拟器里调试该程序image.png

  • objection hook的基本命令是:android hooking watch class_method 方法名 [参数1类型名,参数2类型名...] [--dump-args] [--dump-return] [--dump-backtrace]

这里hook checkflag 函数,在文件中输入一串不重复的数据

Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
>objection -g mobilego explore
Using USB device `Android Emulator 5554`
Agent injected and responds ok!

     _   _         _   _
 ___| |_|_|___ ___| |_|_|___ ___
| . | . | | -_|  _|  _| | . |   |
|___|___| |___|___|_| |_|___|_|_|
      |___|(object)inject(ion) v1.11.0

     Runtime Mobile Exploration
        by: @leonjza from @sensepost

[tab] for command suggestions
com.example.mobilego on (OPPO: 9) [usb] #  android hooking watch class_method game.Game.checkflag --dump-return
(agent) Attempting to watch class game.Game and method checkflag.
(agent) Hooking game.Game.checkflag(java.lang.String)
(agent) Registering job 723570. Type: watch-method for: game.Game.checkflag
com.example.mobilego on (OPPO: 9) [usb] # (agent) [723570] Called game.Game.checkflag(java.lang.String)
(agent) [723570] Return Value: ViLdOlJTePKcMYZFQBSHUCXWIaAGkfbDghjNER
得到打乱后的形式,通过脚本模仿打乱方式,完成解密
Python
1
2
3
4
5
6
example="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl"
back="ViLdOlJTePKcMYZFQBSHUCXWIaAGkfbDghjNER"
crypto="49021}5f919038b440139g74b7Dc88330e5d{6"

for i in example:
    print(crypto[back.index(i)],end="")

  • 恶补: index() 函数用于从列表中找出某个值第一个匹配项的索引位置。

    Text Only
    1
              语法:list.index(x[, start[, end]])<br />                  x-- 查找的对象。   start-- 可选,查找的起始位置。   end-- 可选,查找的结束位置。<br />![image.png](https://cdn.nlark.com/yuque/0/2023/png/40787854/1703860938184-9a601733-eb0c-4f50-af82-c088ebc14d42.png#averageHue=%23201e1c&clientId=u9b21307c-7848-4&from=paste&height=41&id=u688378ac&originHeight=61&originWidth=1462&originalType=binary&ratio=1.5&rotation=0&showTitle=false&size=21812&status=done&style=none&taskId=u40439ddd-8852-4046-a53a-dad5c6db888&title=&width=974.6666666666666)<br />可得D0g3{4c3b5903d11461f94478b7302980e958}
    
  • 获得经验:可以先运行程序看看输出的字符串,然后到反编译软件里搜索输出的报错字符串位置,可以定位主函数!

你见过蓝色的小鲸鱼吗⚓︎

无壳32位
没什么头绪,用findcryto查一下
image.png
image.png
找一下位置image.png
image.png
__CheckForDebuggerJustMyCode应该是个反调试,把它nop了image.png
X查一下交叉引用,看看父级函数什么样image.png
大概是获取了输入和长度,根据题目提示,IpString应该是账号,WindowTextLengthA应该是账号长度
猜测v4可能是密码,v8是密码长度,v2应该是内存地址之类的东西
image.png
37行进去image.png
反调试函数nop掉
是一个判断函数,应该存在密文对比,猜测是前文获取了用户名,将用户名作为密钥blowfish加密了输入的密文,对比成功后输出正确
这里可以用动态调试把cmp过程中调取的用于对比的密文搞出来
image.png
调用cmp函数的位置下个断点
image.png
数据就在call前面压栈的寄存器内image.png取出来都补成两位
连起来就是密文 11A51F049550E2508F17E16CF1632B47
找个在线工具解密(CyberChef的密钥格式支持太少,很痛苦)
注意几个参数的设置
image.png
拼接一下 D0g3{UzBtZTBuZV9EMGczQHRoZWJsdWVmMXNo}

  • chen04师傅那里看到的详细解释:(我这里是猜的)image.png

感觉有点点简单⚓︎

虽然不知道sys是什么东西,但是反正可以放进IDA分析
64位无壳,没有故意藏主函数
image.png
大致能看到在30、31行进行了加密
先是一个魔改RC4image.png
循环的轮数改成了64,最后的异或也有些变化
image.png
然后是魔改的base64
image.png
与传统的base64算法不同,这里取二进制数值的时候有一些变化
image.png
都是三字符转四个字符,但是取的位数发生了如上图的变化
image.png
=判断应该是base64魔改加密后的结果

根据以上分析构建脚本
先逆向出魔改base64的脚本,然后由于RC4是可逆的,魔改rc4基本上抄一遍IDA再跑一下就可以

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
enc="6zviISn2McHsa4b108v29tbKMtQQXQHA+2+sTYLlg9v2Q2Pq8SP24Uw"
b64map="4KBbSzwWClkZ2gsr1qA+Qu0FtxOm6/iVcJHPY9GNp7EaRoDf8UvIjnL5MydTX3eh"
index=[b64map.index(i) for i in enc]+[0]
temp=[]
for i in range(0,len(index),4):  #b64将三个字符变成四个,逆向时每次截取4个字符,转化为三个原文
    get=index[i:i+4] #取4个字符,每个字符对应6位二进制
    temp.append(get[0]|((get[1]&0b11)<<6))
    temp.append((get[1]>>2)|((get[2]&0b1111)<<4))
    temp.append((get[2]>>4)|(get[3]<<2))

hex_list = [hex(num) for num in temp]  
print(hex_list)

#5c 21 7b 33 51 33 38 28 3a 2b 30 40 16 2c 33 25 36 4 38 46 51 3c 25 4a 13 33 39 3b 69 27 4d 29 33 14 33 46 30 31 32 40 6c 00
#RC4再跑一遍

key="the_key_"
S=[]
K=[]
for i in range(64):
    S.append(i)
for j in range(64):
    K.append(ord(key[j % len(key)]))
v6=0
for k in range(64):
    v6=(K[k]+S[k]+v6)%64
    S[k],S[v6]=S[v6],S[k]

v5=0
v6=0
for i in range(len(temp)):
    v5=(v5+1)%64
    v6=(S[v5]+v6)%64
    S[v5],S[v6]=S[v6],S[v5]
    temp[i]^=(v6^v5)&S[(((v6 ^ v5) + S[v6] + S[v5]) % 64)]
print("".join(map(chr,temp)))
运行后得到image.png
D0g3{608292C4-15400BA4-B3299A5C-704C292D}

牢大想你了⚓︎

image.png
可以看到得到的是一个Unity文件
从Lazzaro师傅的blog里可以得到经验
Unity逆向

Unity Dll逆向 一般的 Unity3D 游戏的主逻辑都在 Assembly-CSarp.dll 中,所以需要 dll文件逆向/重新打包 工具。Unity3D开发的游戏,其核心代码都在这个 dll 文件中,所以逆向/修改这个 dll 文件就可以了。

所以我们在文件夹里找 Assembly-CSarp.dll 这个文件
image.png
Unity框架的文件我们用dnspy进行反编译
image.png
GameManager看起来像个正经文件,点开来看一下
image.png
有“牢大”“flag”的字符串,应该是主函数部分
image.png
往下翻看到类似key和密文的东西
image.png
跟进一下encryptedData后面的字符串
image.png
跳转到加密函数位置,标准TEA加密
结合上文得知:密文={ 3363017039,1247970816,549943836,445086378,3606751618,1624361316,3112717362,705210466,3343515702,2402214294,4010321577,2743404694 }
密钥={ 286331153,286331153,286331153,286331153 }
delta=2654435769
由此构建TEA解密脚本

C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

void Decrypt(uint32_t* data, uint32_t* key)
{
    uint32_t v0 = data[0], v1 = data[1];
    uint32_t delta = 2654435769;
    uint32_t sum = delta * 32; //反过来最后一次的sum,循环32次

    for (int i = 0; i < 32; i++)
    {
        v1 -= ((v0 << 4) + key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + key[3]);
        v0 -= ((v1 << 4) + key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + key[1]);
        sum -= delta;
    }

    data[0] = v0;
    data[1] = v1;
} //解密函数

int main()
{
    uint32_t encryptedData[] = 
    { 3363017039,1247970816,549943836,445086378,
     3606751618,1624361316,3112717362,705210466,
     3343515702,2402214294,4010321577,2743404694 };  //12个
    uint32_t key[] = { 286331153,286331153,286331153,286331153 };

    for (int i = 0; i < 12; i += 2)   
    {
        Decrypt(&encryptedData[i], key);
    }

    printf("%s", encryptedData);

    return 0;
}
image.png
得到 flag{it_is_been_a_long_day_without_you_my_friend}

你好,PE⚓︎

无壳32位
有大量的反调试函数__CheckForDebuggerJustMyCode,非常的恶心,手动删除很麻烦,可以搓一个脚本
学过C语言的都知道,被引用的函数是写在main函数外面的,需要的时候进行引用,所以该函数有一个固定的地址
这里的反调试函数也是一样,只要找到了其所在的地址,在每次引用这个地址时都把函数nop掉,就可以绕开反调试了
image.png
随便找一个反调试函数点开,注意在汇编窗口下查看地址
image.pngimage.png
可以看到地址停留在00450C10,继续往下跟是内部的详细代码,不过我们只要把函数入口处地址找到就可以完成patch了

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#批量删除反调试函数
from ida_hexrays import *
from ida_dbg import *
from idaapi import *
from idautils import *
from idc import *
from ida_kernwin import *
'''交叉引用,获取引用0x0450C10(反调)处代码的地址列表'''
for item in CodeRefsTo(0x0450C10, 1):
    '''patch成0x90(nop)'''
    patch_bytes(item,bytes([90]*5))
image.png加载到ida运行,或者Script command写进去运行
运行完了没啥提示,别担心,已经运行成功了。(如果手撸一定要删完,不然调试会出问题)
然后寻找加密主函数
先静态分析往下跟
image.png
注意12行sub_44E753第一个参数是0,第二个参数是疑似输入内容IpAddress,跟进去
image.png
这里只会触发case 0
image.png
这里上文a1是IpAddress,涉及到它的函数是sub_44FCC5
image.png
出现了IpAddress的大量引用,不知道哪个有用,动调尝试
会发现只有19行sub_44ED5C运行后会有字符串输出的变化
image.png
仔细调试会发现应该是在14行位置跳转至真·主函数
下个断点继续动调
F7进入,然后F8到这里停了,打个断点重启
image.png
再来一次
image.png
跑进主函数了
image.png
往上翻,在主函数开头部分按P形成函数,然后F5分析
image.png
image.png
通过len error的字样,我们可以猜测第一个if判断的是字符串长度,猜一下长度为41(紧接着41被改成48,根据答案格式可以猜测,增加的7个字符应当是 D0g3{}和'\0',输入的仅仅是括号内的部分)
image.png
我们也可以进17行确认一下
image.png
显然是在计算flag长度
然后找一下加密函数
image.png
这里22行应该是字符串比较,unk_1013C008点进去就是密文(注意密文对比用了48个字符,从4D往下48个都是密文)
(1013C008)16+(48)10 =(1013 C038)16
整理一下可得密文:
Python
1
2
3
4
5
6
0x4D,0xB8,0x76,0x29,0xF5,0xA9,0x9E,0x59,
0x55,0x56,0xB1,0xC4,0x2F,0x21,0x2C,0x30,
0xB3,0x79,0x78,0x17,0xA8,0xED,0xF7,0xDB,
0xE1,0x53,0xF0,0xDB,0xE9,0x03,0x51,0x5E,
0x09,0xC1,0x00,0xDF,0xF0,0x96,0xFC,0xC1,
0xB5,0xE6,0x62,0x95,0x01,0x00,0x00,0x00,
image.png
F8到21行F7进去
image.png
照例P然后F5反编译(和官方跑出来不一样!红温了!8.3我也试过了,也不一样)
image.png
qword_1013C000是一个被异或的部分,应该是某种密钥
image.png其值为54AA4A9
我这个伪代码和答案有出入,编不出来……拿官方的函数写脚本吧
f79355f2b8a647a8a88fe5e4b375a2d5.pngc0c8b81d97fbd66d107d14d1f4357722.png
抄一下官方的脚本进行分析
C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>

void fdec()
{
    __int64 dq_key = 88777897;  //用于异或的key(54AA4A9)
    BYTE flag[] = {
        0x4D,0xB8,0x76,0x29,0xF5,0xA9,0x9E,0x59,
        0x55,0x56,0xB1,0xC4,0x2F,0x21,0x2C,0x30,
        0xB3,0x79,0x78,0x17,0xA8,0xED,0xF7,0xDB,
        0xE1,0x53,0xF0,0xDB,0xE9,0x03,0x51,0x5E,
        0x09,0xC1,0x00,0xDF,0xF0,0x96,0xFC,0xC1,
        0xB5,0xE6,0x62,0x95,0x01,0x00,0x00,0x00,
    }; //密文
    __int64 p;
    int j, i;
    for (i = 0; i < 6; i++)  //48/8=6轮
    {
        p = *((__int64*)&flag[i * 8]); //每次取8位,形成一个块构成整数
        for (j = 0; j < 64; j++)  //64次加密
        {
            if (p & 1) //就是判断是否>0
            {
                p = ((unsigned __int64)p ^ dq_key) >> 1; //异或之后右移一位
                p |= 0x8000000000000000;//还原符号位1 

            }
            else
            {
                p = (unsigned __int64)p >> 1;  //直接右移一位
            }
        }
        *((__int64*)&flag[i * 8]) = p; //加密之后赋值回去
    }
    for (i = 0; i < 48; i++)  //全部打印出来
        printf("%c", flag[i]);
    printf("\n");
    return;
}

int main(int argc, BYTE* argv[])
{
    fdec();
    return 0;
}
~~devil师傅硬干汇编做出来了……我的汇编太烂了,写不出WP来~~

三、NCTF复现⚓︎

中文编程1⚓︎

无壳32位
运行一下image.png
image.png
搜字符找不到函数
一步步动态调试找一下主函数
image.png
开头下个断点
image.png
走了两步发现主函数sub_40102B
image.png
进去看一下大概是z3
image.png
构建一下脚本(复制的时候为了提高v20[i]编辑效率,可以选中“*v20 + ”部分右键“更改所有匹配项”把所有的都删了)

Python
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from z3 import *
from Crypto.Util.number import *

v20 = []  
for i in range(1, 13):  
    v20.append(Int('v20[' + str(i) + ']')) 

S = Solver()  #创建约束求解器

S.add(v20[1] * 52.0
     + v20[2] * 93.0
     + v20[3] * 15.0
     + v20[4] * 72.0
     + v20[5] * 61.0
     + v20[6] * 21.0
     + v20[7] * 83.0
     + v20[8] * 87.0
     + v20[9] * 75.0
     + v20[10] * 75.0
     + v20[11] * 88.0
     - 7.86241466532e11==0)  #添加约束条件
S.add(v20[1] * 24.0
     + v20[2] * 3.0
     + v20[3] * 22.0
     + v20[4] * 53.0
     + v20[5] * 2.0
     + v20[6] * 88.0
     + v20[7] * 30.0
     + v20[8] * 38.0
     + v20[9] * 2.0
     + v20[10] * 64.0
     + v20[11] * 60.0
     - 3.76271212978e11==0)
S.add(v20[1] * 21.0
     + v20[2] * 33.0
     + v20[3] * 76.0
     + v20[4] * 58.0
     + v20[5] * 22.0
     + v20[6] * 89.0
     + v20[7] * 49.0
     + v20[8] * 91.0
     + v20[9] * 59.0
     + v20[10] * 42.0
     + v20[11] * 92.0
     - 6.47642467922e11==0)
S.add(v20[1] * 60.0
     + v20[2] * 80.0
     + v20[3] * 15.0
     + v20[4] * 62.0
     + v20[5] * 62.0
     + v20[6] * 47.0
     + v20[7] * 62.0
     + v20[8] * 51.0
     + v20[9] * 55.0
     + v20[10] * 64.0
     + v20[11] * 3.0
     - 6.70839740597e11==0)
S.add(v20[1] * 51.0
     + v20[2] * 7.0
     + v20[3] * 21.0
     + v20[4] * 73.0
     + v20[5] * 39.0
     + v20[6] * 18.0
     + v20[7] * 4.0
     + v20[8] * 89.0
     + v20[9] * 60.0
     + v20[10] * 14.0
     + v20[11] * 9.0
     - 5.49200140865e11==0)
S.add(v20[1] * 90.0
     + v20[2] * 53.0
     + v20[3] * 2.0
     + v20[4] * 84.0
     + v20[5] * 92.0
     + v20[6] * 60.0
     + v20[7] * 71.0
     + v20[8] * 44.0
     + v20[9] * 8.0
     + v20[10] * 47.0
     + v20[11] * 35.0
     - 6.6473011328e11==0)

S.add(v20[1] * 78.0
     + v20[2] * 81.0
     + v20[3] * 36.0
     + v20[4] * 50.0
     + v20[5] * 4.0
     + v20[6] * 2.0
     + v20[7] * 6.0
     + v20[8] * 54.0
     + v20[9] * 4.0
     + v20[10] * 54.0
     + v20[11] * 93.0
     - 4.76762422687e11==0)

S.add(v20[1] * 63.0
     + v20[2] * 18.0
     + v20[3] * 90.0
     + v20[4] * 44.0
     + v20[5] * 34.0
     + v20[6] * 74.0
     + v20[7] * 62.0
     + v20[8] * 14.0
     + v20[9] * 95.0
     + v20[10] * 48.0
     + v20[11] * 15.0
     - 6.44352175854e11==0)

S.add(v20[1] * 72.0
      + v20[2] * 78.0
      + v20[3] * 87.0
      + v20[4] * 62.0
      + v20[5] * 40.0
      + v20[6] * 85.0
      + v20[7] * 80.0
      + v20[8] * 82.0
      + v20[9] * 53.0
      + v20[10] * 24.0
      + v20[11] * 26.0
      - 7.87224288556e11==0)

S.add(v20[1] * 89.0
      + v20[2] * 60.0
      + v20[3] * 41.0
      + v20[4] * 29.0
      + v20[5] * 15.0
      + v20[6] * 45.0
      + v20[7] * 65.0
      + v20[8] * 89.0
      + v20[9] * 71.0
      + v20[10] * 9.0
      + v20[11] * 88.0
      - 6.67891172792e11==0)

S.add(v20[1]
      + v20[2] * 8.0
      + v20[3] * 88.0
      + v20[4] * 63.0
      + v20[5] * 11.0
      + v20[6] * 81.0
      + v20[7] * 8.0
      + v20[8] * 35.0
      + v20[9] * 35.0
      + v20[10] * 33.0
      + v20[11] * 5.0
      - 4.17587420064e11==0)


S.check()  #检测是否有解

d=S.model() 

flag = b''  #字节字符串
for i in range(1,12):
     temp = long_to_bytes(d[v20[i]].as_long())
     temp = temp[::-1]
     flag += temp

print(flag)
直接输出会发现每四个字符都是倒过来的image.png
所以加入一个temp逆序输出一下得到 flag{1517e135-aeac-412e-9fe4-91cd02c88290}

本周自己学习过程中遇到的问题和疑问点⚓︎

  • frida安装后无法正常使用5105afc65a09fe5a946fcb55de0d6fc4.png

    无法查看版本号,似乎根本找不到软件位置。csdn上的解决方案都过时了,没有效果。
    ~~(重装后解决了,见了鬼了)~~

  • 配置sui环境时物理机成功了,但是虚拟机kali\ubuntu都失败了,用了魔法都不行……

  • 不会用windbg内核调试
  • 你好PE那题IDA翻出来和官方不一样……可能是版本问题?(8.3也不行的)

情感、思考、观点⚓︎

学海无涯,共同进步!

在团队的感触和建议⚓︎

和师傅们在一起真的很温暖!