In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >
Share
Shulou(Shulou.com)06/01 Report--
Author: Hcamael@ knows that Chuangyu 404 laboratory
Date: November 29, 2019
Original link: https://paper.seebug.org/1090/
Recently, I encountered a situation in the process of studying IoT devices. For an IoT device, the official firmware package is not available, and the relevant firmware package can not be found on the Internet, so I read it directly from flash. Because the system is VxWorks, you can see the flash layout, so you can easily decompose the uboot/firmware from the flash. For firmware, the first half is compressed by lzma, and the second half is compressed by lzma at a certain interval. The symbol information of the firmware is in the latter part. Because I don't know in what format the second half is put into memory with the first half of the code, it's a bit of a hindrance to me in reverse. So I wanted to look at the logic of uboot, but uboot can't be thrown directly into ida for analysis, so I have this article, analyze the uboot format, and how to use ida to analyze uboot.
Uboot format
A normal uboot format should look like this:
$binwalk bootimg.binDECIMAL HEXADECIMAL DESCRIPTION----13648 0x3550 CRC32 polynomial table, big endian14908 0x3A3C uImage header, header size: 64 bytes, header CRC: 0x25ED0948 Created: 2019-12-02 03:39:51, image size: 54680 bytes, Data Address: 0x80010000, Entry Point: 0x80010000, data CRC: 0x3DFB76CD, OS: Linux, CPU: MIPS, image type: Firmware Image, compression type: lzma, image name: "u-boot image" 14972 0x3A7C LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 161184 bytes
And the uboot actually has to be divided into three parts:
1. Slave 0x00-0x346C is part of bootstrap
2.0x346C-0x34AC has header information of uboot image with 0x40 bytes
3. The body of uboot image is from 0x34AC to the end, and the result is compressed by lzma.
So how is uboot generated? Randomly find a uboot source code on Github: https://github.com/OnionIoT/uboot, compile and install it, and view the generation process of uboot.
1. The first step is to compile the bootstrap and uboot source code into two ELF programs using gcc to get bootstrap and uboot
two。 The second step is to use objcopy to convert the two files into binary stream files respectively.
$mips-openwrt-linux-uclibc-objcopy-- gap-fill=0xff-O binary bootstrap bootstrap.bin$ mips-openwrt-linux-uclibc-objcopy-- gap-fill=0xff-O binary uboot uboot.bin$ binwalk u-boot/bootstrapDECIMAL HEXADECIMAL DESCRIPTION -0 0x0 ELF 32-bit MSB executable, MIPS, version 1 (SYSV) 13776 0x35D0 CRC32 polynomial table Big endian28826 0x709A Unix path: / uboot/u-boot/cpu/mips/start_bootstrap.S$ binwalk u-boot/bootstrap.binDECIMAL HEXADECIMAL DESCRIPTION -13648 0x3550 CRC32 polynomial table Big endian$ binwalk u-boot/u-bootDECIMAL HEXADECIMAL DESCRIPTION----0 0x0 ELF, 32-bit MSB executable, MIPS Version 1 (SYSV) 132160 0x20440 U-Boot version string, "U-Boot 1.1.4 (Dec 2 2019) 11:39:50) "132827 0x206DB HTML document header133794 0x20AA2 HTML document footer134619 0x20DDB HTML document header135508 0x21154 HTML document footer135607 0x211B7 HTML document header137363 0x21893 HTML document footer137463 0x218F7 HTML document header138146 0x21BA2 HTML document footer138247 0x21C07 HTML document header139122 0x21F72 HTML document footer139235 0x21FE3 HTML document header139621 0x22165 HTML document footer139632 0x22170 CRC32 polynomial table Big endian179254 0x2BC36 Unix path: / uboot/u-boot/cpu/mips/start.S$ binwalk u-boot/u-boot.binDECIMAL HEXADECIMAL DESCRIPTION -132032 0x203C0 U-Boot version string "U-Boot 1.1.4 (Dec 2 2019 11:39:50) "132699 0x2065B HTML document header133666 0x20A22 HTML document footer134491 0x20D5B HTML document header135380 0x210D4 HTML document footer135479 0x21137 HTML document header137235 0x21813 HTML document footer137335 0x21877 HTML document header138018 0x21B22 HTML document footer138119 0x21B87 HTML document header138994 0x21EF2 HTML document footer139107 0x21F63 HTML document header139493 0x220E5 HTML document footer139504 0x220F0 CRC32 polynomial table Big endian
3. Compress u-boot.bin using lzma algorithm to get u-boot.bin.lzma
$binwalk u-boot/u-boot.bin.lzmaDECIMAL HEXADECIMAL DESCRIPTION----0 0x0 LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes Uncompressed size: 161184 bytes
4. Using mkimage, add 0x40 byte header information to u-boot.bin.lzma to get u-boot.lzming
$binwalk u-boot/u-boot.lzimgDECIMAL HEXADECIMAL DESCRIPTION----0 0x0 uImage header, header size: 64 bytes, header CRC: 0x25ED0948 Created: 2019-12-02 03:39:51, image size: 54680 bytes, Data Address: 0x80010000, Entry Point: 0x80010000, data CRC: 0x3DFB76CD, OS: Linux, CPU: MIPS, image type: Firmware Image, compression type: lzma, image name: "u-boot image" 64 0x40 LZMA compressed data, properties: 0x5D, dictionary size: 33554432 bytes, uncompressed size: 161184 bytes
5. Finally, merge bootstrap.bin and u-boot.lzming together, and then according to the actual size of the required uboot, for example, you need a 128k uboot, and use 0xff at the end to complete it to 128k.
Using ida to process bootstrap binary stream files
In the above structure, there are a few points to pay attention to:
1.Data Address: 0x80010000, Entry Point: 0x80010000 means that after the device is started, the data extracted by uboot through lzma will be stored in the memory address 0x80010000, and then $pc will be set to: 0x80010000, so the first 4 bytes of uboot must be instructions.
2.uncompressed size: 161184 bytes, you can use dd to extract the LZMA data separately, and then use lzma to decompress it. The size of the decompressed data should be the same as this field. If you also want to confirm whether there is a problem with the decompression result, you can use the CRC algorithm to verify it.
The next step is to separate the binary stream from the uboot and throw it into the ida through dd or other programs. First, let's take a look at bootstrap. First, specify the corresponding CPU type. For example, for the above example, you need to set the MIPS big end.
Then we temporarily set the starting address to 0x80010000. After power is turned on, the address of the first execution of CPU is not known by default. Different CPU have different starting addresses. The settings are shown in the following figure:
Bootstrap also has instructions at the beginning, so press C to convert to instructions, as shown in the following figure:
Jump to 0x80010400, followed by a piece of initialization code. The next step is to determine the base address of the program. Because it is mips, we can determine the base address based on $gp.
As shown in the figure above, because the size of bootstrap is 0x3a3c bytes, you can initially estimate the base address as 0x9f000000, so modify the base address below:
And modify it in Options-> General-> Analysis-> Processor specific. Set $gp=0x9F0039A0
At first, the 0x9F0039A0 address belongs to the scope of the got table, and the function address is stored, so the data after the 0x9F0039A0 address is converted to word:
At this point, the processing is finished, and then the reverse work is saved. What the specific bootstrap code has done is not the focus of this article, so it doesn't matter for the time being.
Using ida to process uboot stream files
When dealing with bootstrap, let's take a look at uboot, which is roughly the same as the above approach.
1. Use dd or other programs to separate the uboot data first. two。 Use lzma to extract 3. Throw it to ida, set the CPU type, and set the base address. Because the uboot header clearly defines the base address as 0x80010000, there is no need to determine the base address 4. Also set the first sentence as an instruction
Normally, uboot is in this format, and 0x80010008 is the got table pointer, which is also the value of $gp.
5. Set $gp 6. 0 according to the value of 0x80010008. Dealing with the got table, the address is basically a function pointer and a small number of string pointers. There is also the structure of the uboot command at the end.
At this point, the uboot is considered to be finished with the basic processing, and the follow-up work is reverse, which is not the focus of this article.
Write idapython to deal with uboot automatically
Take the processing flow of uboot as an example, use Python to write an ida plug-in, automatically deal with uboot binary stream files.
1. We set 0x80010000 to the _ _ start function
Idc.add_func (0x80010000) idc.set_name (0x80010000, "_ _ start")
2.0x80010008 is the got table pointer, because we handled the 0x80010000, so the got table pointer address is also automatically translated into code, we need to change to word format.
Idc.del_items (0x80010008) idc.MakeDword (0x80010008) got_ptr = idc.Dword (0x80010008) idc.set_name (idc.Dword (0x80010008), ".got.ptr")
3. Convert the got table to Word format. If it is a string pointer, it will be reflected in the comments.
Def got (): assert (got_ptr) for address in range (got_ptr, end_addr) 4): value = idc.Dword (address) if value = = 0xFFFFFFFF:2019-12-03 15:36:56 Tuesday break idc.MakeDword (address) idaapi.autoWait () if idc.Dword (value)! = 0xFFFFFFFF: func_name = idc.get_func_name (value) if not idc.get_func_name (value): Idc.create_strlit (value Idc.BADADDR) else: funcs.append (func_name)
Ok is basically here, and some .text segment information can be added later, but it is not necessary. The final source code is as follows:
#! / usr/bin/env python#-*-coding=utf-8-*-import idcimport idaapiclass Anlysis: def _ _ init__ (self): self.start_addr = idc.MinEA () self.end_addr = idc.MaxEA () self.funcs = [] def uboot_header (self): idc.add_func (self.start_addr) idc.set_name (self.start_addr "_ _ start") idc.del_items (self.start_addr+ 0x8) idc.MakeDword (self.start_addr+ 0x8) self.got_ptr = idc.Dword (self.start_addr+8) idc.set_name (idc.Dword (self.start_addr+8), ".got.ptr") def got (self): assert (self.got_ptr) for address in range (self.got_ptr, self.end_addr 4): value = idc.Dword (address) if value = = 0xFFFFFFFF: break idc.MakeDword (address) idaapi.autoWait () if idc.Dword (value)! = 0xFFFFFFFF: func_name = idc.get_func_name (value) if not idc.get_func_name (value): Idc.create_strlit (value Idc.BADADDR) else: self.funcs.append (func_name) def get_max_text_addr (self): assert (self.funcs) max_addr = 0 for func_name in self.funcs: addr = idc.get_name_ea_simple (func_name) end_addr = idc.find_func_end (addr) ) if end_addr > max_addr: max_addr = end_addr if max_addr% 0x10 = = 0: self.max_text_addr = max_addr else: self.max_text_addr = max_addr + 0x10-(max_addr% 0x10) def add_segment (self Start, end, name, type_): segment = idaapi.segment_t () segment.startEA = start segment.endEA = end segment.bitness = 1 idaapi.add_segm_ex (segment, name, type_ Idaapi.ADDSEG_SPARSE | idaapi.ADDSEG_OR_DIE) def start (self): # text seg self.uboot_header () self.got () self.get_max_text_addr () self.add_segment (self.start_addr, self.max_text_addr, ".text" "CODE") # end idc.jumpto (self.start_addr) if _ _ name__ = "_ _ main__": print ("Hello World")
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
Support for remote connection protocols such as RDP, VNC, XDMCP, SSH, etc.
© 2024 shulou.com SLNews company. All rights reserved.