Welcome to my blog.
- In the blog, I will record some of the knowledge I have learned.
- Welcome to discuss with me.
Welcome to my blog.
腾讯游戏安全2024决赛-PC-WriteUp 题目解读后,可以分为两个块,一个是写注册机,一个是分析内核shellcode的位置和干了什么 分析USER和KEY 在进行这个题目的时候,发现双机调试不能使用,分析的ark工具也不能使用,基本上这种方式不太行了,但是仍然比不了自己手速!哈哈哈哈!在没有蓝屏的时候用ark dump了一份load.dump.bin,哈哈哈哈 因为题目要求将card.txt放置到C盘根目录:这个时候发现一个现象,如果我不放到根目录下,或者如果我card.txt里面的值被我随便修改的情况下可以进行双机调试不会被检测,这个时候自己有了一点想法,(但是还是先做这个问为主),因为这个时候可以进行双机调试所以自己用双机调试做的USER和KEY分析的东西 load.dump.bin中,可以看到路径的名称为:\\??\\C:\\card.txt,但是回溯不了很烦 还根据ZwCreateFile入手 NTSYSAPI NTSTATUS ZwCreateFile( [out] PHANDLE FileHandle, [in] ACCESS_MASK DesiredAccess, [in] POBJECT_ATTRIBUTES ObjectAttributes, [out] PIO_STATUS_BLOCK IoStatusBlock, [in, optional] PLARGE_INTEGER AllocationSize, [in] ULONG FileAttributes, [in] ULONG ShareAccess, [in] ULONG CreateDisposition, [in] ULONG CreateOptions, [in, optional] PVOID EaBuffer, [in] ULONG EaLength ); 直接看一下ObjectAttributes里面的ObjectName的名字 一般来说如果读取文件来说,用的是ZwCreateFile,进行栈回溯一直跟一直跟,因为在vm中一定要回到text段,这个时候我认为的方式是:参数写入后,进行call lea reg,xxxxxx call vm 但是感觉栈回溯太多了不太行,然后想了一下看了一下这个地址的address模块在这个loader.sys中,计算一下offset = 0x675e20,然后交叉引用回去即可 这个的路径是xor 0xace做到的,我这边直接解密,也可以看到code References的地址 直接windbg分析后,这个位置不难,很好的可以分析user算法的位置: key的算法位置: 这两个位置我是动态调试出来的,大概算法的表示为-进行分割后,user计算后的值转化为10进制,就是key的值 注册机: #include <iostream> using namespace std; uint64_t getkey(string user) { uint32_t encuser = 0; for(int i : user) { encuser = (i + encuser)*0x1003f; } return encuser; } int main() { string user; cout << "input your user: " << endl; cin >> user; cout << "your key : " << getkey(user) << endl; return 0; } 第一问:administrator-4007951923...
腾讯游戏安全2024初赛-PC-WriteUp 可以看到题目说的是有一个exe和一个sys两个pe文件,答案是两个token,那么可以大胆的猜测是R0层一个,R3层一个 因为自己从R0层开始分析的,所以这里分析的过程也从R0层开始 Ring0 Token PS:这里自己有个很大的坑,搞了很久才知道,题目中(关闭windows defender等杀软后,先运行exe后需自行加载sys驱动,驱动加载返回值为31则驱动加载成功。此时,程序会写入两段shellcode到内存中)这个位置我双击调试的时候,因为没有很耐心的等待sys驱动加载完,立刻断下来开始搞的导致无法出现蓝屏的情况,这个问题搞了很久(所以这里要注意一下) 在R3程序启动后,R0程序启动后,R0返回值为0x31,这个一般不是一个正确的返回值 这个时候打开其他的调试工具的时候,会发生蓝屏的现象,蓝屏的错误代码 0xace 根据这个想法来说的话,在驱动加载后返回0x31的情况下,进行了一个检测,并且导致蓝屏,那么很好的可以猜到很可能是起了一个内核线程,直接断PsCreateSystemThread (然后经过漫长的等待,因为驱动加了vmp跑的很慢) 这时候断下后发现这个地址有点不太对劲 直接uf看一下这个地址,这里能看到这个0xACE的值,和上面一堆的xmm的操作,并且这个位置是无模块的,直接dump下来看看是什么 直接丢在ida里f5看一下 这里做了一些xor的操作,我是进行了解密 import numpy as np v7 = np.array([0x4B6D1DDD324B10F0, 0x1E336B548B32934E], dtype=np.uint64) v10 = np.array([0x4B6D1DDD4A7920D5, 0x1E336B548B32934E], dtype=np.uint64) v7_xor = np.bitwise_xor(v7, v10) result_hex = [hex(value) for value in v7_xor] print(result_hex) 解密出来的是token:, %02x 这种东西,这里还是一个while(1),所以直接bp地址过来看看是什么东西 可以发现是DbgPrintEx,但是如果想在调试器中输出需要把该函数的level改了 NTSYSAPI ULONG DbgPrintEx( [in] ULONG ComponentId, [in] ULONG Level, [in] PCSTR Format, ... ); 直接把Level修改成0 token:8b3f14a24d64f3e697957c252e3a5686 这个题也可以直接用winark (https://github.com/BeneficialCode/WinArk)去做,直接看一下system的线程看看有没有奇怪的地址,直接dump即可 Ring3 Token R3程序,主要进行了远线程注入,这里直接hook WriteProcessMemory 这个时候会发现有四个地方写入 Process 25492, lpBaseAddress 00000213AFFA0000, lpBuffer 00007FF689274DA0 Size 1420 Process 25492, lpBaseAddress 00000213AFFA058C, lpBuffer 0000029A6C45C060 Size 4506624 Process 25492, lpBaseAddress 00000213B03EC98C, lpBuffer 000000EC6B2FF140 Size 552 Process 1956, lpBaseAddress 0000004D09CCEAD0, lpBuffer 000000EC6B2FFAA0 Size 4 这里的Size 4设置了标志位,来跟Ring 0层进行Check,这个也就是为什么我们在打开一次黑名单中的调试器的时候,会导致下一次直接报出查询到了,以及Ring 0层检测后进行了蓝屏的原因...
DamCTF CTF rev/incomprehensible #(lambda x:[([l.append((lambda n,u:(lambda f,*a:f(f,*a))((lambda r,i,u:i if i not in u else r(r,(i+1)%16,u+[i])),n%16,u))(c,l))for c in x[::-1]],l)for l in [[]]][0][1])(l[-1])) import base64 l = [b'CoOL N0nCE duD3!'] #key : [1, 3, 4, 5, 6, 0, 7, 8, 14, 2, 15, 9, 12, 10, 11, 13] #en_data : MUIiJmFxRyAnSUQmESoON0QbEy5Hf1EqB0NOFXNLTXleIzMSaRRYID8lcX4WA3RP def padding_data_16(input_data): paddingsize = 16 - len(input_data) % 16 padding = bytes(list(range(1, paddingsize + 1))[::-1]) input_data = padding + input_data return [input_data[i*16:(i+1)*16] for i in range(len(input_data) // 16)] data = padding_data_16(input()....
1: X 主要逻辑在X.dll中,直接使用dnspy进行反编译 可以看到当为42的时候,为判定条件 2: ItsOnFire 是一个apk的文件,直接使用jeb进行反编译,找来找去,发现主要的函数在f b中,实现的AES 代码贴出来 主要的地方: private final long a(byte[] arr_b) { CRC32 cRC320 = new CRC32(); cRC320.update(arr_b); return cRC320.getValue(); } private final byte[] b(String s, byte[] arr_b, SecretKeySpec secretKeySpec0, IvParameterSpec ivParameterSpec0) { Cipher cipher0 = Cipher.getInstance(s); cipher0.init(2, secretKeySpec0, ivParameterSpec0); byte[] arr_b1 = cipher0.doFinal(arr_b); Intrinsics.checkNotNullExpressionValue(arr_b1, "cipher.doFinal(input)"); return arr_b1; } private final File c(int v, Context context0) { Resources resources0 = context0.getResources(); Intrinsics.checkNotNullExpressionValue(resources0, "context.resources"); byte[] arr_b = this....
Wacon CTF https://global.wacon.world/challenges Adult Artist https://github.com/JuliaPoo/Artfuscator 这个题的生成使用的是 Artfuscator 工具,观察了一下生成的101 cases,里面的所有的计算都是线性的计算操作 nop掉无用的指令 import idautils import idc def my_nop(addr, endaddr): while addr < endaddr: patch_byte(addr, 0x90) addr += 1 pattern = "2E C4 E2 71 96 84 9A 0C 80 0E 08" cur_addr = 0x80491FF end_addr = 0x80E69F5 while cur_addr < end_addr: cur_addr = idc.find_binary(cur_addr,SEARCH_DOWN,pattern) print("patch address: " + str(cur_addr)) # 打印提示信息 if cur_addr == idc.BADADDR: break else: my_nop(cur_addr,cur_addr + 11) cur_addr = idc....
周末闲的无聊打了一下SSTF 2023的比赛,由于自己太菜啦,就做出来了一个题 PulpQuest,中间有很多的时间被Seven’s Game - Metal这个题卡住了,等官方的writeup了,最近有空会把剩下没做的题,做一下丢在这个writeup里 PulpQuest 打开后是pulp的游戏,有点类似于小时候玩的那种小型游戏机,直接开启了模拟器和ce快速过一下 由于快速过一下,我直接搞了一下血量看看这个游戏是怎么玩的 需要reverse给的程序,大概看了一下 就一个data.json是有有用信息的 只看到了这个id : 38是和上面图片中的Scroll是有关系的(其实自己的英语不是很好,我把Magic和Orbs都搜了一下 发现只有这里有相关的id 38) 整理一下相关的check 获取了A - P的后 call foo call bar "data": {"abc": ["block",14], "bar": ["block",17], "baz": ["block",18], "boo": ["block",15], "foo": ["block",16], "ork": ["block",5], "qux": ["block",1], "fred": ["block",2], "thud": ["block",9], "corge":["block",13], "enter":["block",0], "plugh":["block",11] block有点像数组,执行的函数是"__blocks": [ ] 括号中的哪个 整理一下foo函数 foo: A,B,C,D,36,23["call","boo"]B,C,D,A E,F,G,H,23,181["call","boo"]F,G,H,E I,J,K,L,181,177["call","boo"]J,K,L,I M,N,O,P,177,36["call","boo"]N,O,P,M A,B,C,D,69,193["call","boo"]B,C,D,A E,F,G,H,193,10["call","boo"]F,G,H,E I,J,K,L,10,99["call","boo"]J,K,L,I M,N,O,P,99,69["call","boo"]N,O,P,M A,B,C,D,246,149["call","boo"]B,C,D,A E,F,G,H,149,183["call","boo"]F,G,H,E I,J,K,L,183,75["call","boo"]J,K,L,I M,N,O,P,75,246["call","boo"]N,O,P,M A,B,C,D,181,94["call","boo"]B,C,D,A E,F,G,H,94,185["call","boo"]F,G,H,E I,J,K,L,185,250["call","boo"]J,K,L,I M,N,O,P,250,181["call","boo"]N,O,P,M A,B,C,D,179,79["call","boo"]B,C,D,A E,F,G,H,79,77["call","boo"]F,G,H,E I,J,K,L,77,56["call","boo"]J,K,L,I M,N,O,P,56,179["call","boo"]N,O,P,M A,B,C,D,107,54["call","boo"]B,C,D,A E,F,G,H,54,201["call","boo"]F,G,H,E I,J,K,L,201,203["call","boo"]J,K,L,I M,N,O,P,203,107["call","boo"]N,O,P,M A,B,C,D,243,64["call","boo"]B,C,D,A E,F,G,H,64,48["call","boo"]F,G,H,E I,J,K,L,48,121["call","boo"]J,K,L,I M,N,O,P,121,243["call","boo"]N,O,P,M A,B,C,D,173,95["call","boo"]B,C,D,A E,F,G,H,95,231["call","boo"]F,G,H,E I,J,K,L,231,47["call","boo"]J,K,L,I M,N,O,P,47,173["call","boo"]N,O,P,M 整理一下boo函数...
1. 部署工作环境 mac的部署环境 安装bochs,因为看了很多贴纸,发现mac安装这个很简单,直接brew就可以 brew install bochs 安装后,在安装目录的/share/doc/bochs下有个sample文件bochsrc-sample.txt可以参考这个在目录下写一个 disk bochsrc.disk: # Bochs启动配置文件 # 1.Bochs在运行中可使用的内存,设为32MB megs: 32 # 2.设置对应真实机器的BIOS和VGA BIOS; 须为绝对路径,Bochs不识相对路径 romimage: file=/usr/local/Cellar/bochs/2.7/share/bochs/BIOS-bochs-latest vgaromimage: file=/usr/local/Cellar/bochs/2.7/share/bochs/VGABIOS-lgpl-latest # 3.选择启动盘符为硬件启动 boot: disk # 4.日志输出 log: bochs.out # 5.关闭鼠标,打开键盘 mouse: enabled=0 keyboard: keymap=/usr/local/Cellar/bochs/2.7/share/bochs/keymaps/x11-pc-us.map # 6.硬盘设置 ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ata0-master: type=disk, path="hd60M.img", mode=flat, cylinders=121, heads=16, spt=63 # ata0-master: type=disk, path="hd60M.img", mode=flat, cylinders=121, heads=16, spt=63 #没有正确的加载Bochs GUI,上面使用term_gui display_library: sdl2 bin/bximage创建虚拟硬盘 根据提示就可以创建,然后根据这个提示来加入disk里面的配置 效果就是 2. 编写MBR主引导记录 当按下主机上的power键后,第一个运行的软件是BIOS,书中有提了三个问题,也是这章所要了解的问题...
ezlua 关键位置在于这里 运行程序发现,随便输入40字节的hex字符,程序会输出attempt to call a string value,调试发现,lua_pcall 的调用返回值为1就是失败,说明传入的lua_state的数据为不合法 经过dump双次对比,合法输入check为0x59B9位置 为除去03外20字节对应hex即可 g0Re-U 因为感觉加了壳,找到start入口点进行dump dump后: 逆推第一步是:减去key值 再进行xor 0x1A 动态调试的时候发现key的值进行了改变 void change_key() { string fuck_key = "kjsuhnmsknw2n46p"; for(int i = 0; i < fuck_key.size(); i++) { if(fuck_key.data()[i] >= 0x62 && fuck_key.data()[i] <= 0x6D) { fuck_key.data()[i] += 0xC; } else if (fuck_key.data()[i] >= 0x42 && fuck_key.data()[i] <= 0x4D) { fuck_key.data()[i] += 0xC; } else if (fuck_key.data()[i] >= 0x6E && fuck_key.data()[i] <= 0x79) { fuck_key....