Aggregator
CVE-2025-48187 | infiniflow ragflow up to 0.18.1 excessive authentication (EUVD-2025-15586)
Submit #578143: PHPGurukul Park Ticketing Management System 2.0 SQL Injection [Duplicate]
Submit #578142: PHPGurukul Park Ticketing Management System 2.0 SQL Injection [Duplicate]
Submit #578141: PHPGurukul Park Ticketing Management System 2.0 SQL Injection [Duplicate]
Submit #578139: PHPGurukul Park Ticketing Management System 2.0 SQL Injection [Duplicate]
Submit #578138: PHPGurukul Park Ticketing Management System 2.0 SQL Injection [Duplicate]
Submit #578137: PHPGurukul Park Ticketing Management System 2.0 SQL Injection [Duplicate]
IGS Arcade Reverse Engineering Series (1) - E2000 Platform Analysis
2010 was the golden era of arcades. As mobile devices and home consoles became widespread, the arcade industry gradually declined. Although some policies were introduced domestically to encourage the amusement gaming equipment industry, the sector has long been out of favor with investors. The 2020 pandemic dealt an even heavier blow to the arcade business.
Back then, 100 RMB might only buy 50 credits; now 100 RMB can buy 200 credits.
I like racing games. Wangan Midnight, Initial D, and Speed Driver have been the hottest games in arcades in recent years, because they have accounts and thus a social component. Some time ago, when I was cracking the player app for Speed Driver 5, I learned that IGS (International Games System) is the company behind the Knights of Valour arcade game I played as a kid and Journey to the West. IGS’s anti-cracking is top-tier across the entire industry, and the Speed Driver series is even known as “uncrackable.”
Last month, the “Super Player” arcade near my home shut down. I felt that sooner or later the Speed Driver series might disappear, so I decided to challenge myself to crack it.
The release order of the IGS Speed Driver series is as follows:
Game Device Model Year Speed Driver: Evolution 2004 Speed Driver 2 E2000 2007 Speed Driver 3 E3000, E3100 2010 Speed Driver 4 E3000, E3100, S3000 2013 Speed Driver 5 S3000 2019I planned to start with the E2000 platform. The difficulty should definitely be lower than PGM (PolyGame Master) because it’s PC-based: there’s no need to emulate a sound card or GPU. The hardware has almost no physical protection, the CPU ISA is x86, the OS is Linux, there’s no anti-debugging, and no VMP—this is basically a tutorial level.
In Asia, the Speed Driver series has influence comparable to Wangan Midnight, Initial D, and Storm Racer G (all of which have been cracked). IGS’s anti-cracking is the most successful: throughout the entire product lifecycle, it was never cracked.
Hardware analysisIn Arcade-docs, you can look up the hardware information of each device and the games it supports. Leveraging my “skill” at scavenging e-waste, I managed to get an E2000 host. There are quite a few enthusiasts abroad buying them too, so the price has gone up.
External interface analysisOn the front there are two RS-485 ports, and the CF card can be removed externally.
Back-side ports, with the very “millennium PC” vibe:
- 12V DC
- 2 x DB9 COM
- 4 x USB 2.0
- RJ45 LAN
- 3.5mm Audio Out
- 25pin + 30pin I/O connector
Given that cracking this doesn’t seem hard, I’m not going to analyze the other components whose silkscreen is covered by stickers—it’s too annoying.
The host I bought came with the game Percussion Master 2008 installed, but Speed Driver 2 also runs.
- Mainboard model: I-JOIN E2000-V256 IH-02 (Advantech)
- A - CPU: Celeron M 370 (1.5 GHz)
- B - Northbridge: unknown
- C - GPU: NVIDIA GeForce 6200 (256 MB, GDDR2)
- D - 2 x DDR 333 256MB
- E - Chipset: Intel 852GME (ICH4-M)
- F - PCI9030, a GPIO chip, likely used for transmitting controller signals.
- G - I/O controller with an LPC interface
- H - A11 BIOS chip SST 49LF004B (PLCC32)
- I - IH-C02 ALTERA EPM3032ALC44-10N CPLD (PLCC44), controller; contains ROM, purpose unknown
- J - IGS EV29LV640-90PCR 8MB EEPROM, DIP 48-pin package, an IGS custom chip. This chip has a label with the game name on it, suggesting the BIOS ROM is also game-related. There may be content related to the V21 chip.
- K - V21, IGS036E, maybe an FPGA or ASIC used to encrypt/process the input/output of control signals
- L - 64K x 16 HIGH-SPEED CMOS STATIC RAM x3
- M - CF card: ADATA 2GB (266X)
- N - IDE HDD connector
I have many ways to get a root shell on the hardware, but I’m more interested in the game loading process. So let’s start with software reverse engineering.
I/O board analysisThese boards are also called control boards. They should be used to connect game controllers such as the steering wheel, brake/throttle, coin acceptor, etc.
They communicate via the 25pin + 30pin I/O connector to the mainboard.
The price may even be higher than the host itself.
In theory, you could use a logic analyzer to capture these sensor signals and then implement control functionality. But I’ve heard the control signals are handled by the V21 chip (ASIC) and may be encrypted. I also don’t plan to clone a control board. These arcade racing games aren’t as fun as Forza Horizon 5. Arcades are cheap these days—if you really want to play, just pay to play at an arcade, or buy a steering wheel setup and play at home.
Filesystem analysisDump the CF card directly. The file size is 2GB. The file command output is:
DOS/MBR boot sector, LInux i386 boot LOader; partition 1 : ID=0x1, active, start-CHS (0x0,1,1), end-CHS (0x2,63,63), startsector 63, 12033 sectors; partition 2 : ID=0x83, start-CHS (0x3,0,1), end-CHS (0x22,63,63), startsector 12096, 129024 sectors; partition 3 : ID=0x83, start-CHS (0x62,0,1), end-CHS (0x399,63,63), startsector 395136, 3322368 sectors; partition 4 : ID=0x83, start-CHS (0x23,0,1), end-CHS (0x61,63,63), startsector 141120, 254016 sectorsBoot process: LILO is used as the MBR, installed directly in the first sector to boot Linux.
+----------------------------------------+ | Master Boot Record Operating system | |----------------------------------------| | LILO ---------------> Linux | | ---> other OS | +----------------------------------------+View the partition information via fdisk. This is a Linux OS with four partitions, contiguous from start to end. Everything after the last partition is 0x00, so there is no hidden partition.
Disk ./percussion_master_2008.img: 1.77 GiB, 1903878144 bytes, 3718512 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x6e4a3fef Device Boot Start End Sectors Size Id Type ./percussion_master_2008.img1 * 63 12095 12033 5.9M 1 FAT12 ./percussion_master_2008.img2 12096 141119 129024 63M 83 Linux ./percussion_master_2008.img3 395136 3717503 3322368 1.6G 83 Linux ./percussion_master_2008.img4 141120 395135 254016 124M 83 LinuxOne notable trait of the E2000 platform layout is that partition 3 and partition 4 are in “reverse” order.
Partition 2 and partition 4 cannot be fully extracted by 7z. binwalk can identify some compressed regions, so it is very likely a heavily modified filesystem.
The purpose of each partition is as follows (later I found the original filesystem types for partitions 2 and 4):
Partition 1: Ext2, Bootloader, kernel Partition 2: IGS CRAMFS, RootFS Partition 3: Ext3, Log Data Partition 4: IGS SquashFS, Game Data Kernel reversingSo far I have not found the rootfs or the game executable; they are most likely located in partition 2 and partition 4. I think reversing the kernel can save a lot of detours. Without relying on the kernel, you could also directly reverse the filesystem format from the raw data, but that’s boring. And whatever extractor you end up writing won’t beat open-source filesystem unpacking tools anyway. First, look at partition 1: it contains a loader and a kernel. The kernel version is shown, but it may not be the correct one.
SD2: LILO (LInux LOder) SD2-OS-61P: Linux kernel x86 boot executable, bzImage, version 2.4.31-IGS_V0.5a (james@Code_Server.linnet.net.tw) #1 Thu Aug 30 19:06:24 CST 2007, RO-rootFS, root_dev 0X305, Normal VGA, setup size 512*6, syssize 0x3b88, jump 0x230 0xe800040000000000 instruction, protocol 2.3LILO has been customized by IGS. It shows “IGS Loader v2.0 Boot Menu 2007/04”, which indicates the base version is lilo-22.8.
There’s nothing interesting to analyze here. Start extracting vmlinux. The kernel file is in bzImage format and needs to be decompressed.
7z x ./SD2-OS-61P -okernel.decompedNext is standard kernel reversing. The first step is to determine the image base. There are many ways to do that; you can refer to my other posts.
Here, after looking twice, you can basically guess it: 0xC0100000.
With the base configured correctly, IDA can automatically identify some xrefs; the rest needs manual recovery. IDA 9.0 changed some APIs, so I had to rewrite some scripts again.
import ida_bytes import ida_segment import ida_funcs import ida_ida def find_and_make_function(start_ea, end_ea, pattern_str): image_base = idaapi.get_imagebase() pattern = ida_bytes.compiled_binpat_vec_t() err = ida_bytes.parse_binpat_str(pattern, image_base, pattern_str, 16) if err: return current_ea = start_ea found_count = 0 while current_ea < end_ea: current_ea, index = ida_bytes.bin_search( current_ea, end_ea, pattern, ida_bytes.BIN_SEARCH_FORWARD | ida_bytes.BIN_SEARCH_NOSHOW) if current_ea == ida_idaapi.BADADDR: break if current_ea % 4 != 0: current_ea += 1 continue if ida_bytes.get_flags(current_ea) & ida_bytes.FF_CODE: if idc.get_func_flags(current_ea) != -1: current_ea += 1 continue seg = ida_segment.getseg(current_ea) if not seg: current_ea += 1 continue if not ida_funcs.add_func(current_ea): print("Create function failed at 0x{:X}".format(current_ea)) else: found_count += 1 current_ea += 4 print("Search finished, {} functions created".format(found_count)) find_and_make_function(0xC0100000, 0xC0508000, "55 89 E5") # You can define function entry opcodes based on your caseOf course, even at this point, not all xrefs are fully recognized. In the data segment, some strings and offsets are not recovered well either, but it doesn’t matter much. If you’re completely stuck, recovering those bits may lead to new discoveries.
Next is to find an entry point for analysis. There’s honestly not much technical content here—I have many approaches, for example starting from filesystem characteristics. But writing everything out would be pedantic and unnecessary.
We can confirm the kernel version is 2.4.31, and the IGS version is v1.0, not v0.5 as shown by the bzImage banner.
From the following strings, we can determine which upstream filesystem versions correspond to IGS’s modified filesystems:
- rofs: cramfs
- shfs: squashfs 2.2
Linux 2.4.31 does not include squashfs. So I directly looked for a squashfs patch. IGS’s modified SHFS is based on squashfs 2.2. https://master.dl.sourceforge.net/project/squashfs/OldFiles/squashfs2.2r2.tar.gz
Linux 2.4 doesn’t support kallsyms, so symbols need to be recovered manually. Some functions like printf, memcpy, str* can be recognized quickly by eye, but I wanted to analyze the system boot process, so I needed to recover some kernel-specific symbols.
For such old devices, cross-compiling on a modern Linux is not feasible. I installed a 32-bit CentOS 5.10 VM, built it successfully, and extracted System.map and vmlinux, making it easier to compare what parts were modified by IGS.
For firmware where you can’t find a ramdisk or rootfs, the first step is definitely to locate sys_mount and the boot parameters in the kernel.
root=/dev/hdc2 ro console=ttyS1,115200 sys_mount("/dev/hdc3", "/PM2008v2", "shfs", flag, data) sys_mount("/dev/hdc4", "/PM2008v2/pm2_data", "ext3", flag, data)From this, we can determine the rootfs should be partition 2, and the game data is in partition 3.
The logic for mounting the ramdisk is located here:
prepare_namespace ->rd_load_disk ->rd_load_image ->identify_ramdisk_imageHere we can confirm IGS supports ramdisks in squashfs and IGS ROFS formats, and we can also identify their magic numbers.
I won’t record the full analysis process. They modified the FS header, which makes the analysis somewhat nasty 🤢.
Extracting the filesystemI analyzed the headers of three custom filesystems on the E2000 platform; the contents are as follows.
IGS SHFS V1 Header struct squashfs_super_block_22_v1 { unsigned int s_magic; // 0xD4AA2682 unsigned int block_size_1:16; unsigned int block_log:16; unsigned int major_number; unsigned int minor_number; unsigned int inodes; unsigned int bytes_used; unsigned int uid_start; unsigned int guid_start; unsigned int inode_table_start; unsigned int directory_table_start; unsigned int flags:8; unsigned int no_uids:8; unsigned int no_guids:8; int mkfs_time /* time of filesystem creation */; squashfs_inode root_inode; unsigned int block_size; unsigned int fragments; unsigned int fragment_table_start; } __attribute__ ((packed)); IGS SHFS V2 HeaderUsing Percussion Master 2008 as an example:
struct squashfs_super_block_22_v2 { unsigned int s_magic; // 0xD4AA2682 char igs_info[64]; // banner unsigned int block_size_1:16; unsigned int block_log:16; unsigned int igs_fs_version_major; // 59 17 23 96 unsigned int igs_fs_version_minor; // E1 5D 70 00 unsigned int major_number; // 31 64 52 E5 unsigned int minor_number; // 92 2C 03 68 unsigned int inodes; unsigned int bytes_used; unsigned int uid_start; unsigned int guid_start; unsigned int inode_table_start; unsigned int directory_table_start; unsigned int flags:8; unsigned int no_uids:8; unsigned int no_guids:8; int mkfs_time /* time of filesystem creation */; squashfs_inode root_inode; unsigned int block_size; unsigned int fragments; unsigned int fragment_table_start; } __attribute__ ((packed)); IGS ROFS V1 Header struct cramfs_inode { unsigned int inode_magic; unsigned int namelen:6, offset:26; unsigned int size:24, gid:8; unsigned int mode:16, uid:16; }; struct cramfs_info { unsigned int crc; unsigned int edition; unsigned int blocks; unsigned int files; }; struct igs_rofs_super_block { unsigned int magic1; // 0x81006e6a unsigned int future; char igs_info[64]; unsigned int size; unsigned int magic2; // 0xD4AA2682 unsigned int flags; unsigned int padding; cramfs_info fsid; char name[64]; cramfs_inode root[2]; }; igs_rofs_super_block File;By porting the headers above into cramfs-tools and squashfs-tools, you can extract the filesystem perfectly, and you can also detect whether files are corrupted. I have uploaded the code to GitHub: https://github.com/gorgiaxx/igs-toolkits
This version is not hard to extract, but the next version (E3000) introduces encryption.
Player @novacosmic00 previously asked me to help extract files for GoGoBall. He said he had already decrypted files from other games, but GoGoBall was the only one he couldn’t decrypt. I tried extracting with my modified tools and found the file CRC was wrong, but most files could still be extracted.
After I finished extracting the firmware and talked with @novacosmic00, I learned that someone had researched this two years ago and wrote extraction scripts.
https://github.com/batteryshark/igstools/tree/main/scripts
The author may have inferred the structs by analyzing filesystem contents and reverse-engineering address patterns. That’s also a valid approach, but the downside is that extracted files can be messy, and you can’t detect CRC errors.
shadow-The shadow file clears the root password by default.
root:x:13130:0:99999:7::: test::13074:0:99999:7:::This is the original file:
root:$1$qAw/5vcb$x9rPCAwLMdRBQXwlq1zG70:13130:0:99999:7::: test:$1$JjP1oLAJ$xilZIedv3S3jbs8oTZAad1:13074:0:99999:7::: Anti-cracking/PM2008v2/PM2008v2 has stripped symbols, and from string patterns it also looks like a normal loader.
But in reality, if you run it on your own computer, it will overwrite the first 512k of your partition with zeros. I actually ran it back then—thankfully I didn’t run as root, and my disk was NVMe. Who would have thought this 18-year-old game still had this trick 🙈. I had never touched this field before; apparently arcade anti-cracking often includes many “suicidal” logics.
The next post will analyze the in-game protection mechanism.
ReferencesIGS Arcade 逆向系列(一)- E2000平台分析
2010年是街机的黄金时代,随着移动终端和家用游戏机普及,街机行业也逐渐走向没落,尽管国内出台了一些政策鼓励游戏游艺设备行业发展,但此行业在未来一直都不被资本看好。2020 疫情更是给电玩行业带来了很大的打击。
在以前,100元可能只能买50个币,现在100元可以买200个币。
我喜欢赛车游戏,湾岸Midnight、头文字D、Speed Driver是近几年电玩城最火的游戏,因为它有账号功能,具备社交属性。前段时间在破解极速5的玩家APP,才知道IGS (鈊象电子)就是我小时候玩的三国战记和西游的厂商,IGS反破解在整个行业都是顶尖的,竞速游戏的极速系列更是号称无人可破解。
上个月,我家旁边的大玩家电玩城倒闭了,我感觉迟早有一天极速系列游戏会消失,便想挑战破解极速系列游戏。
IGS 极速系列发布顺序如下:
Game Device Model Year Speed Driver:Evolution Evolution 2004 Speed Driver 2 E2000 2007 极速 3 E3000, E3100 2010 极速 4 E3000, E3100, S3000 2013 极速 5 S3000 2019我计划从E2000平台开始破解,难度肯定比PGM(PolyGame Master)更低,因为是基于PC开发的,不需要额外模拟声卡和显卡。硬件几乎没有物理保护,CPU指令集是x86,OS是Linux,没有反调试,也没有VMP,这不就是新手村吗。
Speed Driver系列在亚洲影响力媲美湾岸Midnight,头文字D,雷动G(都被破解了)。IGS的反破解是最成功的,在整个产品生命周期内都未被破解。
硬件分析在 Arcade-docs 可以查询到每个设备的硬件信息和支持的游戏 凭借我擅长的淘电子垃圾能力,已经搞到一台E2000主机。国外有不少爱好者购买,所以价格涨上去了。
外部接口分析正面有两个RS-485接口,并且CF卡可以从外部拆卸
背面接口,具有千禧年PC的接口特点
- 12V DC
- 2 x DB9 COM
- 4 x USB 2.0
- RJ45 LAN
- 3.5mm Audio Out
- 25pin + 30pin 的I/O口
考虑到这个破解难度不高,其他贴了贴纸遮盖丝印的元件就不分析了,太麻烦
我买的这个主机安装了 Percussion Master 2008 游戏,但极速2也能运行
- 主板型号:I-JOIN E2000-V256 IH-02 (研华)
- A - CPU:Celeron M 370 (1.5 GHz)
- B - 北桥:未知
- C - GPU:NVIDIA GeForce 6200 (256 MB, GDDR2)
- D - 2 x DDR 333 256MB
- E - Chipset: Intel 852GME (ICH4-M)
- F - PCI9030,是GPIO芯片,可能用于游戏控制器的信号传输。
- G - I/O 控制器 有LPC接口
- H - A11 BIOS芯片 SST 49LF004B(PLCC32)
- I - IH-C02 ALTERA EPM3032ALC44-10N CPLD (PLCC44), 控制器,里面有ROM,用途不详
- J - IGS EV29LV640-90PCR 8MB EEPROM,DIP 48-Pin 封装,IGS定制的芯片。这个芯片专门贴了游戏名称的标签,说明BIOS ROM 也和游戏有关。可能会有跟V21芯片相关的内容。
- K - V21,IGS036E,也许是一颗FPGA或者ASIC,用于加密处理控制信号的输入输出
- L - 64K x 16 HIGH-SPEED CMOS STATIC RAM x3
- M - CF卡:ADATA 2GB (266X)
- N - IDE硬盘接口
我有很多种办法拿硬件的root shell,但我对游戏加载的过程更感兴趣,因此先做软件逆向分析吧。
I/O板分析这几块板子又称控制板,应该是用于连接游戏控制器,比如方向盘、刹车油门、投币器之类的。
通过连接主板的25pin + 30pin 的I/O口 进行通信
价格可能比主机本体还贵
应该可以使用逻辑分析仪来捕获这些传感器信号,然后实现控制功能。但据说控制信号由V21芯片(ASIC)处理,可能会加密。我也不打算去仿制一个控制板。这种街机游戏没有地平线5好玩。现在电玩城也便宜,真想玩的话,就直接花钱去电玩城,或者买一套方向盘在家里玩。
文件系统分析直接dump CF卡,文件大小2GB,file命令的回显如下:
DOS/MBR boot sector, LInux i386 boot LOader; partition 1 : ID=0x1, active, start-CHS (0x0,1,1), end-CHS (0x2,63,63), startsector 63, 12033 sectors; partition 2 : ID=0x83, start-CHS (0x3,0,1), end-CHS (0x22,63,63), startsector 12096, 129024 sectors; partition 3 : ID=0x83, start-CHS (0x62,0,1), end-CHS (0x399,63,63), startsector 395136, 3322368 sectors; partition 4 : ID=0x83, start-CHS (0x23,0,1), end-CHS (0x61,63,63), startsector 141120, 254016 sectors启动过程,LILO作为MBR,直接安装在第一个扇区,用来引导Linux
+----------------------------------------+ | Master Boot Record Operating system | |----------------------------------------| | LILO ---------------> Linux | | ---> other OS | +----------------------------------------+通过fdisk查看分区信息。是Linux操作系统,四个分区,并首尾连续,最后一个分区之后的内容,都是0x00,不存在隐藏分区
Disk ./percussion_master_2008.img: 1.77 GiB, 1903878144 bytes, 3718512 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x6e4a3fef Device Boot Start End Sectors Size Id Type ./percussion_master_2008.img1 * 63 12095 12033 5.9M 1 FAT12 ./percussion_master_2008.img2 12096 141119 129024 63M 83 Linux ./percussion_master_2008.img3 395136 3717503 3322368 1.6G 83 Linux ./percussion_master_2008.img4 141120 395135 254016 124M 83 LinuxE2000平台的分区有一个特点,第三分区和第四分区,顺序是反的。
第二分区和第四分区,7z无法完全提取,binwalk能识别出一些压缩区域,因此大概率是经过了魔改的文件系统。
每个分区的用途如下(最后我找到了分区2,4的原始文件系统类型):
Partition 1: Ext2, Bootloader, kernel Partition 2: IGS CRAMFS, RootFS Partition 3: Ext3, Log Data Partition 4: IGS SquashFS, Game Data Kernel 逆向目前未找到rootfs和游戏程序,他们大概率位于第二分区和第四分区。 我认为逆向kernel可以少走不少弯路。不依赖内核,其实可以直接硬逆出文件系统的格式,但这样很无聊,而且最终写出来的extractor,肯定比不了开源的文件系统解压工具。 首先看第一个分区,有一个 loader 和 kernel。显示了内核版本,但是这里不一定是正确的版本。
SD2: LILO (LInux LOder) SD2-OS-61P: Linux kernel x86 boot executable, bzImage, version 2.4.31-IGS_V0.5a (james@Code_Server.linnet.net.tw) #1 Thu Aug 30 19:06:24 CST 2007, RO-rootFS, root_dev 0X305, Normal VGA, setup size 512*6, syssize 0x3b88, jump 0x230 0xe800040000000000 instruction, protocol 2.3LILO经过了IGS 定制开发,会显示,IGS Loader v2.0 Boot Menu 2007/04,可判断版本是lilo-22.8
这里没什么好分析的,直接开始提取vmlinux,内核文件是bzImage格式,需要解压
7z x ./SD2-OS-61P -okernel.decomped接下来就是普通的内核逆向,第一步计算基址,基址有很多种确定方法,可以参考我其他文章。
这里多看两眼就猜出来了,0xC0100000
基址配置正确,IDA就可以自动识别出一些交叉引用,剩下的需要手动还原。IDA 9.0修改了一些API,又得重新写一下脚本。
import ida_bytes import ida_segment import ida_funcs import ida_ida def find_and_make_function(start_ea, end_ea, pattern_str): image_base = idaapi.get_imagebase() pattern = ida_bytes.compiled_binpat_vec_t() err = ida_bytes.parse_binpat_str(pattern, image_base, pattern_str, 16) if err: return current_ea = start_ea found_count = 0 while current_ea < end_ea: current_ea, index = ida_bytes.bin_search( current_ea, end_ea, pattern, ida_bytes.BIN_SEARCH_FORWARD | ida_bytes.BIN_SEARCH_NOSHOW) if current_ea == ida_idaapi.BADADDR: break if current_ea % 4 != 0: current_ea += 1 continue if ida_bytes.get_flags(current_ea) & ida_bytes.FF_CODE: if idc.get_func_flags(current_ea) != -1: current_ea += 1 continue seg = ida_segment.getseg(current_ea) if not seg: current_ea += 1 continue if not ida_funcs.add_func(current_ea): print("Create function failed at 0x{:X}".format(current_ea)) else: found_count += 1 current_ea += 4 print("Search finished, {} functions created".format(found_count)) find_and_make_function(0xC0100000, 0xC0508000, "55 89 E5") # 可以根据实际情况自己定义 function entry opcode当然到这里还没有完全识别出全部交叉引用,在data段,还有一些字符串和offset还原的不是很好,但影响不大,实在是没有思路的话,就把这些内容还原,说不定会有新发现。
接下来就是找分析切入点,实在没啥技术含量,我有很多种方案,比如从文件系统特征入手之类的,但全写出来就像说“茴字有五种写法”一样搞笑。
可以确认内核版本是 2.4.31,并且IGS版本是v1.0,而不是bzImage显示的v0.5。
根据下列字符串,可以确定IGS魔改文件系统对应的原始文件系统版本
- rofs:cramfs
- shfs: squashfs 2.2
Linux 2.4.31 没有squashfs,直接找squashfs的patch,IGS魔改SHFS是基于squashfs2.2。 https://master.dl.sourceforge.net/project/squashfs/OldFiles/squashfs2.2r2.tar.gz
Linux 2.4没有支持kallsysm,因此需要手动还原符号。一些printf,memcpy,str之类的函数可以快速一眼看出来,但是我要分析系统启动过程,所以需要还原一些内核专用的符号。
这种老设备,在新的linux下没有办法交叉编译,我安装了一个CentOS 5.10的32位虚拟机,成功编译,提取出 System.map 和 vmlinux,这样就可以方便对比IGS魔改的部分。
对于这种找不到ramdisk或者rootfs的固件,第一步肯定是找到kernel里的sys_mount和boot parameters
root=/dev/hdc2 ro console=ttyS1,115200 sys_mount("/dev/hdc3", "/PM2008v2", "shfs", flag, data) sys_mount("/dev/hdc4", "/PM2008v2/pm2_data", "ext3", flag, data)这里可以确定,rootfs应该是第二分区,游戏数据在第三分区。
挂在ramdisk的逻辑,位于此处
prepare_namespace ->rd_load_disk ->rd_load_image ->identify_ramdisk_image在此次可以确定IGS 支持 squashfs 和 igs rofs 格式的ramdisk。并且可以确定它们的magic。
分析过程就不记录了,他们把 FS 的header魔改了,分析起来有一些恶心🤢。
提取文件系统我分析了 E2000 平台的三种自定义文件系统 header,内容如下。
IGS SHFS V1 Header struct squashfs_super_block_22_v1 { unsigned int s_magic; // 0xD4AA2682 unsigned int block_size_1:16; unsigned int block_log:16; unsigned int major_number; unsigned int minor_number; unsigned int inodes; unsigned int bytes_used; unsigned int uid_start; unsigned int guid_start; unsigned int inode_table_start; unsigned int directory_table_start; unsigned int flags:8; unsigned int no_uids:8; unsigned int no_guids:8; int mkfs_time /* time of filesystem creation */; squashfs_inode root_inode; unsigned int block_size; unsigned int fragments; unsigned int fragment_table_start; } __attribute__ ((packed)); IGS SHFS V2 Header以 Percussion Master 2008 为例
struct squashfs_super_block_22_v2 { unsigned int s_magic; // 0xD4AA2682 char igs_info[64]; // banner unsigned int block_size_1:16; unsigned int block_log:16; unsigned int igs_fs_version_major; // 59 17 23 96 unsigned int igs_fs_version_minor; // E1 5D 70 00 unsigned int major_number; // 31 64 52 E5 unsigned int minor_number; // 92 2C 03 68 unsigned int inodes; unsigned int bytes_used; unsigned int uid_start; unsigned int guid_start; unsigned int inode_table_start; unsigned int directory_table_start; unsigned int flags:8; unsigned int no_uids:8; unsigned int no_guids:8; int mkfs_time /* time of filesystem creation */; squashfs_inode root_inode; unsigned int block_size; unsigned int fragments; unsigned int fragment_table_start; } __attribute__ ((packed)); IGS ROFS V1 Header struct cramfs_inode { unsigned int inode_magic; unsigned int namelen:6, offset:26; unsigned int size:24, gid:8; unsigned int mode:16, uid:16; }; struct cramfs_info { unsigned int crc; unsigned int edition; unsigned int blocks; unsigned int files; }; struct igs_rofs_super_block { unsigned int magic1; // 0x81006e6a unsigned int future; char igs_info[64]; unsigned int size; unsigned int magic2; // 0xD4AA2682 unsigned int flags; unsigned int padding; cramfs_info fsid; char name[64]; cramfs_inode root[2]; }; igs_rofs_super_block File;将上述文件header,移植到cramfs-tools和squashfs-tools,就可以完美提取文件系统,并且还可以发现文件是否损坏。我已经将代码上传至github。https://github.com/gorgiaxx/igs-toolkits
这个版本提取难度不高,但下个版本E3000就用上加密了。
玩家 @novacosmic00 之前请我帮忙提取 GoGoBall 的文件,但他说他已经解密了其他游戏的文件。唯独 GoGoBall 解不了。用我修改的工具尝试提取,发现文件CRC不对,但还是能提取出大部分。
在我提取完固件之后,和玩家 @novacosmic00 沟通,才知道两年前有人研究过这个,并写了提取脚本。
https://github.com/batteryshark/igstools/tree/main/scripts
作者可能是根据文件系统内容,找出地址规律反推结构体的,这也是一种办法,但缺点是提取出来的文件可能比较混乱,而且无法检测CRC错误。
shadow-shadow文件,默认都清空了root密码
root:x:13130:0:99999:7::: test::13074:0:99999:7:::这是原始的文件
root:$1$qAw/5vcb$x9rPCAwLMdRBQXwlq1zG70:13130:0:99999:7::: test:$1$JjP1oLAJ$xilZIedv3S3jbs8oTZAad1:13074:0:99999:7::: 反破解/PM2008v2/PM2008v2,符号去除了,并且根据字符串特征,也像是正常的loader
但实际上,如果在自己电脑运行,他会把你分区前512k写0。我当时居然运行了,还好我没给root,而且硬盘是NVME的。谁能想到这个18年前的游戏,还有这一手🙈。以前从来没接触过这个领域,据说街机的反破解有很多自杀式逻辑。
下一篇文章将分析游戏内部的保护机制
参考IGS Arcade 逆向系列(一)- E2000平台分析
2010年是街机的黄金时代,随着移动终端和家用游戏机普及,街机行业也逐渐走向没落,尽管国内出台了一些政策鼓励游戏游艺设备行业发展,但此行业在未来一直都不被资本看好。2020 疫情更是给电玩行业带来了很大的打击。
在以前,100元可能只能买50个币,现在100元可以买200个币。
我喜欢赛车游戏,湾岸Midnight、头文字D、Speed Driver是近几年电玩城最火的游戏,因为它有账号功能,具备社交属性。前段时间在破解极速5的玩家APP,才知道IGS (鈊象电子)就是我小时候玩的三国战记和西游的厂商,IGS反破解在整个行业都是顶尖的,竞速游戏的极速系列更是号称无人可破解。
上个月,我家旁边的大玩家电玩城倒闭了,我感觉迟早有一天极速系列游戏会消失,便想挑战破解极速系列游戏。
IGS 极速系列发布顺序如下:
Game Device Model Year Speed Driver:Evolution Evolution 2004 Speed Driver 2 E2000 2007 极速 3 E3000, E3100 2010 极速 4 E3000, E3100, S3000 2013 极速 5 S3000 2019我计划从E2000平台开始破解,难度肯定比PGM(PolyGame Master)更低,因为是基于PC开发的,不需要额外模拟声卡和显卡。硬件几乎没有物理保护,CPU指令集是x86,OS是Linux,没有反调试,也没有VMP,这不就是新手村吗。
Speed Driver系列在亚洲影响力媲美湾岸Midnight,头文字D,雷动G(都被破解了)。IGS的反破解是最成功的,在整个产品生命周期内都未被破解。
硬件分析在 Arcade-docs 可以查询到每个设备的硬件信息和支持的游戏 凭借我擅长的淘电子垃圾能力,已经搞到一台E2000主机。国外有不少爱好者购买,所以价格涨上去了。
外部接口分析正面有两个RS-485接口,并且CF卡可以从外部拆卸
背面接口,具有千禧年PC的接口特点
- 12V DC
- 2 x DB9 COM
- 4 x USB 2.0
- RJ45 LAN
- 3.5mm Audio Out
- 25pin + 30pin 的I/O口
考虑到这个破解难度不高,其他贴了贴纸遮盖丝印的元件就不分析了,太麻烦
我买的这个主机安装了 Percussion Master 2008 游戏,但极速2也能运行
- 主板型号:I-JOIN E2000-V256 IH-02 (研华)
- A - CPU:Celeron M 370 (1.5 GHz)
- B - 北桥:未知
- C - GPU:NVIDIA GeForce 6200 (256 MB, GDDR2)
- D - 2 x DDR 333 256MB
- E - Chipset: Intel 852GME (ICH4-M)
- F - PCI9030,是GPIO芯片,可能用于游戏控制器的信号传输。
- G - I/O 控制器 有LPC接口
- H - A11 BIOS芯片 SST 49LF004B(PLCC32)
- I - IH-C02 ALTERA EPM3032ALC44-10N CPLD (PLCC44), 控制器,里面有ROM,用途不详
- J - IGS EV29LV640-90PCR 8MB EEPROM,DIP 48-Pin 封装,IGS定制的芯片。这个芯片专门贴了游戏名称的标签,说明BIOS ROM 也和游戏有关。可能会有跟V21芯片相关的内容。
- K - V21,IGS036E,也许是一颗FPGA或者ASIC,用于加密处理控制信号的输入输出
- L - 64K x 16 HIGH-SPEED CMOS STATIC RAM x3
- M - CF卡:ADATA 2GB (266X)
- N - IDE硬盘接口
我有很多种办法拿硬件的root shell,但我对游戏加载的过程更感兴趣,因此先做软件逆向分析吧。
I/O板分析这几块板子又称控制板,应该是用于连接游戏控制器,比如方向盘、刹车油门、投币器之类的。
通过连接主板的25pin + 30pin 的I/O口 进行通信
价格可能比主机本体还贵
应该可以使用逻辑分析仪来捕获这些传感器信号,然后实现控制功能。但据说控制信号由V21芯片(ASIC)处理,可能会加密。我也不打算去仿制一个控制板。这种街机游戏没有地平线5好玩。现在电玩城也便宜,真想玩的话,就直接花钱去电玩城,或者买一套方向盘在家里玩。
文件系统分析直接dump CF卡,文件大小2GB,file命令的回显如下:
DOS/MBR boot sector, LInux i386 boot LOader; partition 1 : ID=0x1, active, start-CHS (0x0,1,1), end-CHS (0x2,63,63), startsector 63, 12033 sectors; partition 2 : ID=0x83, start-CHS (0x3,0,1), end-CHS (0x22,63,63), startsector 12096, 129024 sectors; partition 3 : ID=0x83, start-CHS (0x62,0,1), end-CHS (0x399,63,63), startsector 395136, 3322368 sectors; partition 4 : ID=0x83, start-CHS (0x23,0,1), end-CHS (0x61,63,63), startsector 141120, 254016 sectors启动过程,LILO作为MBR,直接安装在第一个扇区,用来引导Linux
+----------------------------------------+ | Master Boot Record Operating system | |----------------------------------------| | LILO ---------------> Linux | | ---> other OS | +----------------------------------------+通过fdisk查看分区信息。是Linux操作系统,四个分区,并首尾连续,最后一个分区之后的内容,都是0x00,不存在隐藏分区
Disk ./percussion_master_2008.img: 1.77 GiB, 1903878144 bytes, 3718512 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x6e4a3fef Device Boot Start End Sectors Size Id Type ./percussion_master_2008.img1 * 63 12095 12033 5.9M 1 FAT12 ./percussion_master_2008.img2 12096 141119 129024 63M 83 Linux ./percussion_master_2008.img3 395136 3717503 3322368 1.6G 83 Linux ./percussion_master_2008.img4 141120 395135 254016 124M 83 LinuxE2000平台的分区有一个特点,第三分区和第四分区,顺序是反的。
第二分区和第四分区,7z无法完全提取,binwalk能识别出一些压缩区域,因此大概率是经过了魔改的文件系统。
每个分区的用途如下(最后我找到了分区2,4的原始文件系统类型):
Partition 1: Ext2, Bootloader, kernel Partition 2: IGS CRAMFS, RootFS Partition 3: Ext3, Log Data Partition 4: IGS SquashFS, Game Data Kernel 逆向目前未找到rootfs和游戏程序,他们大概率位于第二分区和第四分区。 我认为逆向kernel可以少走不少弯路。不依赖内核,其实可以直接硬逆出文件系统的格式,但这样很无聊,而且最终写出来的extractor,肯定比不了开源的文件系统解压工具。 首先看第一个分区,有一个 loader 和 kernel。显示了内核版本,但是这里不一定是正确的版本。
SD2: LILO (LInux LOder) SD2-OS-61P: Linux kernel x86 boot executable, bzImage, version 2.4.31-IGS_V0.5a (james@Code_Server.linnet.net.tw) #1 Thu Aug 30 19:06:24 CST 2007, RO-rootFS, root_dev 0X305, Normal VGA, setup size 512*6, syssize 0x3b88, jump 0x230 0xe800040000000000 instruction, protocol 2.3LILO经过了IGS 定制开发,会显示,IGS Loader v2.0 Boot Menu 2007/04,可判断版本是lilo-22.8
这里没什么好分析的,直接开始提取vmlinux,内核文件是bzImage格式,需要解压
7z x ./SD2-OS-61P -okernel.decomped接下来就是普通的内核逆向,第一步计算基址,基址有很多种确定方法,可以参考我其他文章。
这里多看两眼就猜出来了,0xC0100000
基址配置正确,IDA就可以自动识别出一些交叉引用,剩下的需要手动还原。IDA 9.0修改了一些API,又得重新写一下脚本。
import ida_bytes import ida_segment import ida_funcs import ida_ida def find_and_make_function(start_ea, end_ea, pattern_str): image_base = idaapi.get_imagebase() pattern = ida_bytes.compiled_binpat_vec_t() err = ida_bytes.parse_binpat_str(pattern, image_base, pattern_str, 16) if err: return current_ea = start_ea found_count = 0 while current_ea < end_ea: current_ea, index = ida_bytes.bin_search( current_ea, end_ea, pattern, ida_bytes.BIN_SEARCH_FORWARD | ida_bytes.BIN_SEARCH_NOSHOW) if current_ea == ida_idaapi.BADADDR: break if current_ea % 4 != 0: current_ea += 1 continue if ida_bytes.get_flags(current_ea) & ida_bytes.FF_CODE: if idc.get_func_flags(current_ea) != -1: current_ea += 1 continue seg = ida_segment.getseg(current_ea) if not seg: current_ea += 1 continue if not ida_funcs.add_func(current_ea): print("Create function failed at 0x{:X}".format(current_ea)) else: found_count += 1 current_ea += 4 print("Search finished, {} functions created".format(found_count)) find_and_make_function(0xC0100000, 0xC0508000, "55 89 E5") # 可以根据实际情况自己定义 function entry opcode当然到这里还没有完全识别出全部交叉引用,在data段,还有一些字符串和offset还原的不是很好,但影响不大,实在是没有思路的话,就把这些内容还原,说不定会有新发现。
接下来就是找分析切入点,实在没啥技术含量,我有很多种方案,比如从文件系统特征入手之类的,但全写出来就像说“茴字有五种写法”一样搞笑。
可以确认内核版本是 2.4.31,并且IGS版本是v1.0,而不是bzImage显示的v0.5。
根据下列字符串,可以确定IGS魔改文件系统对应的原始文件系统版本
- rofs:cramfs
- shfs: squashfs 2.2
Linux 2.4.31 没有squashfs,直接找squashfs的patch,IGS魔改SHFS是基于squashfs2.2。 https://master.dl.sourceforge.net/project/squashfs/OldFiles/squashfs2.2r2.tar.gz
Linux 2.4没有支持kallsysm,因此需要手动还原符号。一些printf,memcpy,str之类的函数可以快速一眼看出来,但是我要分析系统启动过程,所以需要还原一些内核专用的符号。
这种老设备,在新的linux下没有办法交叉编译,我安装了一个CentOS 5.10的32位虚拟机,成功编译,提取出 System.map 和 vmlinux,这样就可以方便对比IGS魔改的部分。
对于这种找不到ramdisk或者rootfs的固件,第一步肯定是找到kernel里的sys_mount和boot parameters
root=/dev/hdc2 ro console=ttyS1,115200 sys_mount("/dev/hdc3", "/PM2008v2", "shfs", flag, data) sys_mount("/dev/hdc4", "/PM2008v2/pm2_data", "ext3", flag, data)这里可以确定,rootfs应该是第二分区,游戏数据在第三分区。
挂在ramdisk的逻辑,位于此处
prepare_namespace ->rd_load_disk ->rd_load_image ->identify_ramdisk_image在此次可以确定IGS 支持 squashfs 和 igs rofs 格式的ramdisk。并且可以确定它们的magic。
分析过程就不记录了,他们把 FS 的header魔改了,分析起来有一些恶心🤢。
提取文件系统我分析了 E2000 平台的三种自定义文件系统 header,内容如下。
IGS SHFS V1 Header struct squashfs_super_block_22_v1 { unsigned int s_magic; // 0xD4AA2682 unsigned int block_size_1:16; unsigned int block_log:16; unsigned int major_number; unsigned int minor_number; unsigned int inodes; unsigned int bytes_used; unsigned int uid_start; unsigned int guid_start; unsigned int inode_table_start; unsigned int directory_table_start; unsigned int flags:8; unsigned int no_uids:8; unsigned int no_guids:8; int mkfs_time /* time of filesystem creation */; squashfs_inode root_inode; unsigned int block_size; unsigned int fragments; unsigned int fragment_table_start; } __attribute__ ((packed)); IGS SHFS V2 Header以 Percussion Master 2008 为例
struct squashfs_super_block_22_v2 { unsigned int s_magic; // 0xD4AA2682 char igs_info[64]; // banner unsigned int block_size_1:16; unsigned int block_log:16; unsigned int igs_fs_version_major; // 59 17 23 96 unsigned int igs_fs_version_minor; // E1 5D 70 00 unsigned int major_number; // 31 64 52 E5 unsigned int minor_number; // 92 2C 03 68 unsigned int inodes; unsigned int bytes_used; unsigned int uid_start; unsigned int guid_start; unsigned int inode_table_start; unsigned int directory_table_start; unsigned int flags:8; unsigned int no_uids:8; unsigned int no_guids:8; int mkfs_time /* time of filesystem creation */; squashfs_inode root_inode; unsigned int block_size; unsigned int fragments; unsigned int fragment_table_start; } __attribute__ ((packed)); IGS ROFS V1 Header struct cramfs_inode { unsigned int inode_magic; unsigned int namelen:6, offset:26; unsigned int size:24, gid:8; unsigned int mode:16, uid:16; }; struct cramfs_info { unsigned int crc; unsigned int edition; unsigned int blocks; unsigned int files; }; struct igs_rofs_super_block { unsigned int magic1; // 0x81006e6a unsigned int future; char igs_info[64]; unsigned int size; unsigned int magic2; // 0xD4AA2682 unsigned int flags; unsigned int padding; cramfs_info fsid; char name[64]; cramfs_inode root[2]; }; igs_rofs_super_block File;将上述文件header,移植到cramfs-tools和squashfs-tools,就可以完美提取文件系统,并且还可以发现文件是否损坏。我已经将代码上传至github。https://github.com/gorgiaxx/igs-toolkits
这个版本提取难度不高,但下个版本E3000就用上加密了。
玩家 @novacosmic00 之前请我帮忙提取 GoGoBall 的文件,但他说他已经解密了其他游戏的文件。唯独 GoGoBall 解不了。用我修改的工具尝试提取,发现文件CRC不对,但还是能提取出大部分。
在我提取完固件之后,和玩家 @novacosmic00 沟通,才知道两年前有人研究过这个,并写了提取脚本。
https://github.com/batteryshark/igstools/tree/main/scripts
作者可能是根据文件系统内容,找出地址规律反推结构体的,这也是一种办法,但缺点是提取出来的文件可能比较混乱,而且无法检测CRC错误。
shadow-shadow文件,默认都清空了root密码
root:x:13130:0:99999:7::: test::13074:0:99999:7:::这是原始的文件
root:$1$qAw/5vcb$x9rPCAwLMdRBQXwlq1zG70:13130:0:99999:7::: test:$1$JjP1oLAJ$xilZIedv3S3jbs8oTZAad1:13074:0:99999:7::: 反破解/PM2008v2/PM2008v2,符号去除了,并且根据字符串特征,也像是正常的loader
但实际上,如果在自己电脑运行,他会把你分区前512k写0。我当时居然运行了,还好我没给root,而且硬盘是NVME的。谁能想到这个18年前的游戏,还有这一手🙈。以前从来没接触过这个领域,据说街机的反破解有很多自杀式逻辑。
下一篇文章将分析游戏内部的保护机制
参考