Simple and crude so encryption and decryption implementation, so decryption

Source: Internet
Author: User

Simple and crude so encryption and decryption implementation, so decryption

Reprint from http://bbs.pediy.com/showthread.php? T = 191649

I have never understood how the. so file is decrypted when it is loaded. I don't know how it works and how it works. I recently reviewed various materials and had some ideas. I can see that there are no similar posts in the forum, so I will post them as study notes. Limited by the level, this course does not find some specific implementation ideas of the Android platform. These methods are based on the Implementation ideas of other platforms and the YY of this course. There will certainly be many omissions and errors, thank you very much for your correction!

Simple and crude so encryption and decryption implementation
I. Overview
Using the dynamic link library to implement the core part of the android application can combat the reverse to a certain extent. Because of the existence of ida and other artifacts, the core part needs to be encrypted. In my opinion, there are two ways to implement the dynamic link library encryption: 1. Source Code; 2. No source code. Encryption without source code is similar to shelling the window platform and shelling the. dex file. You need to analyze the file, insert the decryption code in the appropriate place, and correct some parameters. If the source code is available, the decryption code can be constructed and the decryption process can be completed when. so is loaded. (Of course, after the application loads the. so file, the. so data in the memory has been decrypted and can be directly dump for analysis. At the same time, there are some ways to combat dump, which will not be expanded here ).
The following sections only discuss the source code method and analyze some feasible implementation methods. It mainly includes the analysis of ELF headers (not the meaning of each field); encryption and decryption based on specific sections and specific functions (not complex encryption algorithms ).

Ii. Analysis of ELF headers for Dynamic Link Libraries
There is a lot of information on the Internet about the ELF file format, and it is well written and detailed. I will not repeat it here. If you are not familiar with it, I suggest you check it out first. In the following content, I mainly analyze the fields in the ELF header from the Link View and load view, hoping to provide readers with some ideas for correcting the ELF file header.
Here, I will list the fields in the ELF header:
Typedef struct {
Unsigned char e_ident [EI_NIDENT];/* File identification .*/
Elf32_Half e_type;/* File type .*/
Elf32_Half e_machine;/* Machine architecture .*/
Elf32_Word e_version;/* ELF format version .*/
Elf32_Addr e_entry;/* Entry point .*/
Elf32_Off e_phoff;/* Program header file offset .*/
Elf32_Off e_shoff;/* Section header file offset .*/
Elf32_Word e_flags;/* Architecture-specific flags .*/
Elf32_Half e_ehsize;/* Size of ELF header in bytes .*/
Elf32_Half e_phentsize;/* Size of program header entry .*/
Elf32_Half e_phnum;/* Number of program header entries .*/
Elf32_Half e_shentsize;/* Size of section header entry .*/
Elf32_Half e_shnum;/* Number of section header entries .*/
Elf32_Half e_shstrndx;/* Section name strings section .*/
} Elf32_Ehdr;
The e_ident, e_type, e_machine, e_version, e_flags, and e_ehsize fields are fixed. The e_entry address is related to the file type. E_phoff, e_phentsize, and e_phnum are related to the Mount view. e_shoff, e_shentsize, e_shnum, and e_shstrndx are related to the Link View. Currently, e_ehsize = 52 bytes, e_shentsize = 40 bytes, and e_phentsize = 32 bytes.
Let's take a look at the arrangement structure of the two views:

Directly, you can get some information: The Program header is behind the ELF header, and the Section Header is at the end of the ELF File. Then we can launch:
E_phoff = sizeof (e_ehsize );
Size of the entire ELF File = e_shoff + e_shnum * sizeof (e_shentsize) + 1
The value of the e_shstrndx field is related to strip. Before Strip:. shstrtab is not the last section. Then e_shstrndx = e_shnum-1-2;

After strip, the. symtab and. strtab sections at the end of the dynamic link library will be removed. Then e_shstrndx = e_shnum-1.

The. so file generated using ndk under \ libs \ armeabi \ is strip and packaged into apk. You can find the strip. so file in \ obj \ local \ armeabi. Here we can take the http://bbs.pediy.com/showthread.php? T = Fixed the. so file mentioned in post 188793. If e_shoff and e_shnum are both changed to any value, it is troublesome to modify them.
It seems that e_shoff, e_shnum, and other section-related information are arbitrarily modified, without affecting the use of the. so file. This is indeed the case. At least two aspects are provided to prove this:
1. so file ing in memory

I believe that you know about the elf load (execution) view. The. so file is mapped to the memory in segment units. In the figure, the section in the red area is not mapped to the memory. Of course, it cannot be found in the segment.
2. Android linker source code
There is an important struct soinfo in linker. h source code. Some fields are listed below:
Struct soinfo {
Const char name [SOINFO_NAME_LEN]; // so full name
Elf32_Phdr * phdr; // address of the Program header
Int phnum; // number of segments
Unsigned * dynamic; // point to. dynamic.
// The following four members are related to the. hash table.
Unsigned nbucket;
Unsigned nchain;
Unsigned * bucket;
Unsigned * chain;

Unsigned * preinit_array;
Unsigned preinit_array_count;
// The two members can only appear in the executable file

// Point to the initialization code, which is prior to the main function, that is, it is called by linker during loading. In linker. c, we can see :__ linker_init-> link_image-> call_constructors-> call_array
Unsigned * init_array;
Unsigned init_array_count;
Void (* init_func) (void );
// Similar to init_array, it is executed only after the end of main.
Unsigned * fini_array;
Unsigned fini_array_count;
Void (* fini_func) (void );
}
In addition, linker. c also has a lot to prove. In essence, the linker is based on the so file parsed by the load view.
Based on the above conclusions, we will analyze the fields in the ELF header.
1) The e_ident [EI_NIDENT] field contains the magic number, byte order, length, and version, followed by 0. For Android linker, use the verify_elf_object function to check the magic number and determine whether it is a. so file. Therefore, we can write data to the position, at least to the Zero Filling position in the back. Unfortunately, I tested fedora 14, but I cannot write data to the Zero Filling position. The linker reports a non-Zero Filling error.
2) for Android linker, it does not care about the e_type, e_machine, e_version, and e_flags fields. It can be modified to other data (only for analysis and no actual measurement)
3) for the dynamic link library, the e_entry address is meaningless, because when the program is loaded, the set jump address is the address of the dynamic connector, this field can be filled with data.
4) when loading so, it has nothing to do with the link view, that is, the fields e_shoff, e_shentsize, e_shnum, and e_shstrndx can be modified at will. After the modification, you can use readelf, ida, and other tools to open it. Various errors will be reported. I believe you have already seen this.
5) since so loading is closely related to the loading view, fields such as e_phoff, e_phentsize, and e_phnum cannot be moved.

According to the above conclusion, it is easy to open the so file with errors by various tools. You can try it. Here is not an example. You will see it later.

Iii. encryption and decryption based on specific sections
Section-based encryption and decryption refers to encrypting specific sections of the so file and decrypting the so file when it is loaded. The following example is provided.
Suppose there is a shelldemo application that calls a native method to return a string for UI display. In the native method, call the getString method to return a string for the native method to return. I need to encrypt the getString method. Here, the getString method is stored in. mytext (specify _ attribute _ (section (". mytext");), that is, the. mytext needs to be encrypted.
Encryption process:
1) read the section offset shoff, shnum, and shstrtab from the so file header.
2) read the string in the shstrtab and store it in the str space.
3) read the section header from the shoff position and store it in shdr.
4) use shdr-> sh_name to index the str string and compare it with. mytext. If it does not match, continue reading
5) read and save the. mytext content in the content using the shdr-> sh_offset and shdr-> sh_size fields.
6) do not use complex encryption algorithms for ease of understanding. Here, only all content is reversed, that is, * content = ~ (* Content );
7) write the content back to the so file.
8) to verify the conclusion that the section Field in section 2 can be modified at will, write shdr-> addr to the ELF header e_shoff, write the memory blocks of shdr-> sh_size and addr to e_entry, that is, ehdr. e_entry = (length <16) + nsize. Of course, this also simplifies the decryption process. Another benefit is that if you modify the so file header and put it back, the program cannot run.

During decryption, make sure that the decryption function is called when so is loaded. The function declaration is: init_getString _ attribute _ (constructor )). (You can also use the c ++ constructor to implement it. In essence, it is also implemented using attribute)
Decryption process:
1) the dynamic linker calls init_getString through call_array
2) Init_getString first calls the getLibAddr method to obtain the start address of the so file in the memory.
3) read the first 52 bytes, that is, the ELF header. Get the. mytext Memory loading address through e_shoff, and get the. mytext size and memory block by ehdr. e_entry.
4) modify the read and write permissions of the memory block where mytext is located.
5) decrypt the [e_shoff, e_shoff + size] data in the memory region, that is, the reverse operation: * content = ~ (* Content );
6) modify the read and write permissions in the memory area.
(The data in the code segment is decrypted and the write permission is required. If you decrypt the data segment, you do not need to change the permission to perform the operation directly)

Use readelf to view the encrypted so file:

The running result is very simple. For the source code, see the attachment.

Note: not all sections can be fully added, and some data cannot be encrypted. For example, if you encrypt the. text file directly, the crt-related code is also encrypted and can only be selectively encrypted. The following describes how to implement

4. encryption and decryption based on specific functions
The above encryption and decryption methods are simple and crude. This method is used. If the ELF header section is restored, it is easy to find that so has an additional section. Therefore, data in the section that already exists in ELF can be encrypted to some extent.
Similar to the preceding example, the name is shelldemo2, but native directly returns the string to the UI. You need to encrypt the Java_com_example_shelldemo2_MainActivity_getString function. Encryption and decryption are implemented based on the loading view. It should be noted that if the encrypted function is declared as static, the function will not appear in. dynsym, and cannot be decrypted by the function name in the load view. Of course, you can also use a clever method, similar to the previous section, to write the address and length information to the so header. Java_com_example_shelldemo2_MainActivity_getString must be called, so it must be found in. dynsym.
Encryption process:
1) read the file header and obtain information about e_phoff, e_phentsize, and e_phnum.
2) locate DYNAMIC through the p_type field in Elf32_Phdr. As you can see, DYNAMIC is. dynamic section. Obtain the start position and length of the file from the p_offset and p_filesz fields.

3) traverse. dynamic and find the offset and. dynstr size in. dynsym,. dynstr, And. hash section. In my testing environment, the d_tag of the. hash defined by elf. h In fedora 14 and windows7 Cygwin x64 is DT_GNU_HASH, while that in the android source code is DT_HASH.
4) Calculate the hash value based on the function name
5) locate the bucket whose subscript hash % nbuckets is based on the hash value, and read it according to the value in the bucket. the Elf32_Sym symbol of the corresponding index in dynsym; it is found in. the corresponding string in dynstr is compared with the function name. If not, find the next Elf32_Sym symbol Based on chain [hash % nbuckets] until it is found or the chain is terminated. The description here is a little complicated and can be directly written into the code.
For (I = bucket [funHash % nbucket]; I! = 0; I = chain [I]) {
If (strcmp (dynstr + (funSym + I)-> st_name, funcName) = 0 ){
Flag = 0;
Break;
}
}
6) after finding the Elf32_Sym symbol corresponding to the function, you can find the position and size of the function based on the st_value and st_size fields.
7) The subsequent steps are the same as those in the previous section.

The decryption process is a reverse encryption process, which is roughly the same. There are only some minor differences, as shown below:
1) Find the starting address of the so file in the memory.
2) You also need to find Phdr through the so file header. After you find PT_DYNAMIC from Phdr, you need to take the p_vaddr and p_filesz Fields instead of p_offset.
3) Subsequent operations are similar to encryption, so we will not repeat them here. When decrypting data in the memory area, you also need to pay attention to the read and write permissions.

Encrypted effect:

The running result is the same as that in the previous section.

V. References
Http://blog.csdn.net/forlong401/article/details/12060605
ELF File Format
Android linker source code: bionic \ linker
Android libc source code: bionic \ libc \ bionic
Google: ELF Link View and loading View
------------------------------------------------------------------------
I wrote a crackme.apk registration machine program for everyone to play. Input 3 ~ 10-bit username and regcodes, 8-bit verification code, character range: ~ Z, ~ Z, 0 ~ 9. If the verification succeeds, the message congratulation is displayed! You crack it !.
Attachment:
Shelldemo.zip.
Shelldemo2.zip.
CrackMe.apk.

The last pdf. This is too messy.
Simple brute-force so * for reprinting, please indicate the source of @ PEdiy.com

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.