Code reuse attribute reserved binary shared library reconstruction and dynamic slimming method, system and equipment and medium
Dynamically loading the shared library through function division and delay binding mechanisms, solving the problem of redundant code in the shared library, achieving efficient memory utilization and security improvement, and adapting to dynamic loading and multi-process environments.
Patent Information
- Application Number
- CN202510417154.9
- Authority / Receiving Office
- CN · China
- Patent Type
- Applications(China)
- Current Assignee / Owner
- Filing Date
- 2025-04-03
- Publication Date
- 2025-07-04
AI Technical Summary
The existing technology cannot effectively solve the resource waste and security risks caused by redundant code in shared libraries, especially the inability to maintain the functional integrity and security of shared libraries in a dynamic loading environment.
The code partition of the binary shared library is divided by function, the shared library is loaded dynamically using the delay binding mechanism, and the page cache is managed at the operating system kernel layer to avoid redundant code loading and copying on write, and to achieve code slimming.
It improves the loading efficiency and memory utilization of shared libraries, enhances system security, prevents code reuse attacks, and supports dynamic loading and code sharing in multi-process environments.
Smart Images

Figure CN120255949A_ABST
Abstract
Description
Technical Field
[0001] The present invention belongs to the technical field of software shared libraries, and particularly relates to a method, system, device and medium for reconstructing and dynamically slimming a binary shared library while retaining code reuse attributes. Background Art
[0002] The original intention of designing shared libraries is to improve code reusability, reduce program size and memory occupancy. However, with the continuous increase of functions, the code size of shared libraries gradually expands, containing a large amount of redundant and unused code parts. This code bloat not only increases the storage and memory consumption of shared libraries, but also brings security risks. The accumulation of redundant code provides exploitable vulnerabilities for attackers. In particular, code reuse attacks have become a major hidden danger in modern information systems. As the code of shared libraries expands, attackers use the method of code reuse to exploit vulnerabilities or unused functions in redundant code to construct precise attack vectors, and then bypass conventional security protection measures to carry out system intrusion. Since the redundant code in shared libraries may not be fully security-reviewed, they often hide potential vulnerabilities, which provides opportunities for attackers. For example, Return-Oriented Programming (ROP) attacks construct malicious programs by splicing legal instructions in redundant code of shared libraries, and then bypass the protection mechanism to execute operations specified by attackers. Against code reuse attacks, existing defense measures include Address Space Layout Randomization (ASLR), Data Execution Prevention (DEP), Control Flow Integrity (CFI) and Code Debloating, etc. ASLR increases the difficulty of ROP attacks by randomizing memory addresses; DEP prohibits code execution in specific memory areas to prevent stack overflow attacks; CFI ensures the legality of program control flow to prevent the execution of ROP chains; Code Debloating reduces the attack surface by removing redundant code. However, these methods have their limitations. ASLR is easily bypassed by information leakage, and DEP cannot effectively prevent modern ROP attacks because attackers can utilize existing code blocks; CFI may bring performance overhead and is insufficient in protecting against data-oriented attacks; if Code Debloating is inaccurate, it may affect the normal function of the program [Chen Meihan. A Selective Randomization Technique for Shared Libraries Based on Code Debloating [D]. Xidian University, 2023. DOI: 10.27389 / d.cnki.gxadu.2023.004130.]. Therefore, existing solutions have not fundamentally solved the potential security risks in shared libraries.
[0003] Existing deflation schemes mainly remove redundant code statically or dynamically eliminate unused code at runtime. These schemes have some limitations [Chris Porter, Girish Mururu, Prithayan Barua, and Santosh Pande. 2020. BlankIt library debloating: getting what you want instead of cutting what you don’t. In Proceedings of the 41st ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI 2020). Association for Computing Machinery, New York, NY, USA, 164–180.]: First, static deflation methods perform permanent and irrecoverable code deletion, resulting in a very limited scope of applicability for the deflated shared library and potentially increasing memory costs; second, many deflation methods have poor compatibility with kernel-level functions, triggering copy-on-write when modifying code pages, increasing memory consumption and performance overhead; finally, current schemes cannot seamlessly support the dynamic loading of shared libraries and typically only work in the case of static shared libraries. These problems limit the effectiveness and performance of existing deflation schemes and do not fully address the resource waste and security risks brought by redundant code. For example, Trimmer [Hashim Sharif, Muhammad Abubakar, Ashish Gehani, and Fareed Zaffar. 2018. TRIMMER: application specialization for code debloating. In Proceedings of the 33rd ACM / IEEE International Conference on Automated Software Engineering (ASE'18). Association for Computing Machinery, New York, NY, USA, 329–339.] removes redundant functional code in a program through configuration data provided by the user. These configuration data are usually static parameters defined by the user at compile time and are treated as constants. During the compilation process, Trimmer uses customized compilation optimization techniques to analyze and delete functional modules in the program that are irrelevant to the current requirements, thereby reducing the size of the program and improving execution efficiency.This method ensures that only the required functions are retained, and other unnecessary parts are removed. However, this solution is overly dependent on static configuration and cannot adapt to the dynamic changes during program runtime, resulting in the deletion of necessary functions or the failure to remove redundant functions.
[0004] In summary, the existing technologies mainly have the following disadvantages:
[0005] 1. Existing static deflation methods usually destroy the shared characteristics of shared libraries, causing multiple processes to be unable to share the same library code, which goes against the original intention of designing shared libraries.
[0006] 2. The load-time / runtime deflation method triggers the copy-on-write (CoW) mechanism when modifying the code page, which means that each new process may trigger new physical page allocation and copying operations during execution, resulting in additional memory overhead and affecting the overall performance of the system.
[0007] 3. Existing deflation methods often do not support the dynamic loading of shared libraries at all, which makes it impossible for programs to load functions or modules of shared libraries according to actual needs during runtime, thus unable to make full use of the dynamic loading mechanism of modern operating systems and restricting the flexibility of memory optimization and function expansion. Summary of the Invention
[0008] To overcome the problems existing in the above-mentioned prior art, the present invention aims to disclose a method, system, device, and medium for reconstructing and dynamically slimming binary shared libraries while retaining code reuse attributes. By analyzing the dependency relationships between shared library functions in the offline stage, the shared library is divided into non-overlapping code partitions and the binary shared library file is reconstructed accordingly. During program runtime, the loader dynamically loads the shared library through the lazy binding mechanism and rewrites the code page as needed, thereby avoiding the loading of redundant code and unnecessary memory occupation; the rewrite operation does not trigger the copy-on-write mechanism, reducing physical memory consumption; at the same time, this method supports the dynamic loading of shared libraries and retains the code reuse characteristics, ensuring the functional integrity of the shared library, improving runtime performance, and enhancing system security.
[0009] To achieve the above object, the present invention adopts the following technical solutions:
[0010] A method for reconstructing and dynamically slimming binary shared libraries while retaining code reuse attributes, specifically including the following steps:
[0011] Step 1: Partition the code of the binary shared library by function, ensuring that each code partition contains only a single functional module, and reconstruct the binary shared library file based on this to obtain a function dependency file and a pointer information file. The content of the function dependency file is the exported functions of the binary shared library and their dependent function information; using the exported functions of the binary shared library as keywords, the corresponding values are all the binary shared library functions called by the exported functions in the binary shared library; the pointer information file is the information required by the randomization method.
[0012] Step 2: Based on the files of the binary shared library reconstructed in Step 1, start code slimming: When the user executes a C language program, the custom loader obtains the binary shared library functions required by the C language program through the lazy binding mechanism, and combines with the function dependency file obtained during the process of reconstructing the binary shared library files in Step 1. By comparing the binary shared library functions called by the C language program with the content of the function dependency file obtained in Step 1, it is determined that the C language program actually calls the exported functions and their dependent functions in the binary shared library, and the code slimming function is started.
[0013] Step 3: Perform dynamic slimming of the binary shared library files: After starting the code slimming function, manage the page cache content at the operating system kernel layer through the system call module. The loader passes the obtained binary shared library exported function and its dependent function information as parameters of the system call function into the kernel; the system call function uses the binary shared library exported function and its dependent function information to write relevant content into the page cache as needed to achieve code slimming; since the user-mode process will trigger the copy-on-write mechanism when modifying the page cache of the shared library file, it is necessary to modify the page table entry permissions of the corresponding pages in the page cache with kernel-mode identity to make it writable, so as to avoid the additional physical memory overhead caused by copy-on-write; in addition, the system call module randomly modifies the relevant information related to symbol references when loading the binary shared library for the first time, so that when the C language program runs normally, the lazy binding mechanism can calculate the target function position according to the new address, realizing the randomization of the shared library code segment.
[0014] Each line of the function dependency file described in Step 1 uses the starting address of the exported function of the binary shared library as the keyword, followed by the offset pairs of all the binary shared library functions that the exported function depends on; the content of the pointer information file includes the base address, target address, offset, pointer size, and specific value of the pointer, and is stored in text form.
[0015] The specific method of Step 1 is as follows:
[0016] Through offline components including the SVF pointer analysis framework, compiler plug-in, and Egalito binary recompilation framework, perform function dependency analysis, pointer analysis, and reconstruction on the files of the target binary shared library.
[0017] Step 1.1, the source code file of the binary shared library converts the source code into an intermediate representation IR through a compiler; then, the compiler plugin intervenes, uses the SVF pointer analysis framework to obtain the call relationships of each function in the shared library file, and stores these relationships using the adjacency matrix data structure to obtain a function call graph.
[0018] Step 1.2, after obtaining the call graph, taking the exported functions of the binary shared library as the starting point, initializing an empty set, and traversing the call graph through breadth-first search, adding all functions that can be directly or indirectly reached from the exported functions to the set until the set no longer changes, thus completing the construction of function clustering; using the Egalito binary recompilation framework, intercepting address allocation, reallocating new addresses for each function according to the information of function clustering, and ensuring memory alignment at the same time to reconstruct the binary shared library file. The reconstructed binary shared library is divided into multiple functional modules, each module corresponds to an independent code partition, and is aligned with the memory page; finally, the binary shared library reconstruction file, function dependency analysis file, and pointer information file are output.
[0019] The content of the function dependency analysis file uses the exported functions of the binary shared library as keywords, and the value corresponding to the keyword is all the binary shared library functions called by the exported function in the binary shared library; the pointer information file is the information required by the randomization method.
[0020] The specific method of step 2 is as follows:
[0021] The user executes a C language program, and the custom loader obtains the binary shared library functions required by the C language program through the lazy binding mechanism, that is, when the C language program first calls a certain function in the binary shared library, the lazy binding mechanism is triggered, and the lazy binding mechanism of the loader calculates the real address of the shared library function and fills this address into the GOT table of the C language program; therefore, when the program starts, it does not immediately resolve all binary shared library functions, but when it is first called, the loader dynamically finds the actual address of the function and obtains in real time the exported functions of the binary shared library actually called by the C language program, including their function names and starting addresses; subsequently, compare the exported functions of the called binary shared library with the content of the function dependency relationship file obtained in advance in step 1, find the corresponding exported functions of the binary shared library and all the functions they depend on, and start the code slimming function.
[0022] The specific method of step 3 is as follows:
[0023] Inside the _dl_lookup_symbol_x function of the custom loader in the lazy binding's _dl_fixup, add the functional logic code for obtaining and comparing dependency information, that is, compare with the function dependency relationship file obtained in step 1 according to the information of the called binary shared library function, obtain the offset information of all dependent functions, and pass the offset information of all dependent functions as parameters to the operating system call for code slimming in the operating system kernel;
[0024] When the C language program accesses the real address of the binary shared library function calculated by the lazy binding mechanism of the loader during the execution of the C language program in step 2, the control is handed over to the operating system kernel; the kernel first checks whether the memory page where the address is located has been mapped to the physical address. If so, no page fault is triggered and the program executes normally; if not, it means that this page is accessed for the first time, then the operating system kernel triggers a page fault exception and triggers page fault handling; before triggering page fault handling, the operating system kernel determines whether this page fault is legal. If it is legal, the page fault handling process starts; during the page fault handling process, the operating system kernel will first check whether the page is in the page cache. If it hits the cache, it directly uses the data in the cache; otherwise, it means that there is no corresponding page in the existing page cache, and it is necessary to find the file content from the disk, paste the file content into the page cache, load the page content from the disk into the physical memory, and update the page table entry;
[0025] After the kernel completes page fault handling, first grant write permissions to the relevant page table entries and synchronize the granting of write permissions to the relevant page table entries to the page cache so that subsequent modifications will not trigger the copy-on-write mechanism; then officially perform code slimming. First, clear all the page cache content of the binary shared library, and then based on the obtained starting offset of the dependent functions, obtain the page numbers of the exported functions and their dependent functions of the binary shared library called in step 2, and then according to the page numbers, write the exported functions and their dependent functions of the binary shared library into the corresponding positions in the page cache in sequence according to the offset values; finally, only the exported functions and their dependent functions of the binary shared library required by the C language program are retained in the memory, and the rest of the useless code is cleared, realizing the slimming of the binary shared library code; finally, the kernel restores the original permissions of the page table entries to ensure the normal execution of the program.
[0026] A binary shared library reconstruction and dynamic slimming system that retains the code reuse attribute, including a binary shared library reconstruction file, a custom loader module, and a system call module;
[0027] The binary shared library reconstruction file is used in Step 1. By reorganizing and optimizing the binary code of the shared library, efficient memory usage and functional modularity are achieved. By analyzing the function dependency relationships of the shared library, a call graph is constructed to identify the dependencies between functions. Then, using the method of function clustering, the functions of the shared library are divided into non-overlapping code partitions to ensure that each partition corresponds to a specific functional module. On this basis, metadata information is collected to provide function-level granularity support for subsequent code slimming.
[0028] The customized loader module is used in Step 2. By combining the customized loader with the lazy binding mechanism, information about the shared library functions actually called by the C language program is obtained. Using the lazy binding mechanism, the shared library partially supports dynamic loading and dynamic linking methods. Regardless of which loading method the shared library uses, when the C language program calls a shared library function, the lazy binding mechanism will be triggered to calculate the actual address of the function, thereby obtaining the exported functions of the shared library actually called by the C language program, including their function names and starting addresses. The exported functions of the shared library being called are compared with the content of the function dependency file pre-obtained in Step 1 to find the corresponding exported functions of the shared library and all the functions they depend on, and the code slimming function is started.
[0029] The system call module is used in Step 3. Modify the page cache information of the shared library file in memory with the identity of the kernel state. By calling the operating system kernel, the page table entries corresponding to the page cache in physical memory are modified, thereby adding write permissions and modifying the page cache content.
[0030] A binary shared library reconstruction and dynamic slimming device that retains code reuse attributes, includes:
[0031] A memory for storing computer programs;
[0032] A processor for executing the computer program to perform the binary shared library reconstruction and dynamic slimming method according to Steps 1 to 3.
[0033] A computer-readable storage medium stores a computer program, characterized in that when the computer program is executed by a processor, it can implement binary shared library reconstruction and dynamic slimming based on the binary shared library reconstruction and dynamic slimming method.
[0034] Compared with the prior art, the present invention has the following beneficial effects:
[0035] 1. Through function dependency relationship reconstruction, the present invention divides the shared library into multiple independent functional modules, thereby realizing the reconstruction of the binary file of the shared library. Compared with the prior art, the present invention performs preliminary code slimming on the shared library file in the offline stage, effectively reducing redundant code and improving the loading efficiency and memory utilization rate.
[0036] 2. The present invention utilizes a lazy binding mechanism to obtain the required shared library functions. The lazy binding mechanism determines the shared library functions required by the target program only during program runtime, thus ensuring that the functions obtained are the ones actually used. Compared with the prior art, the present invention has the following characteristics: First, the lazy binding mechanism can determine the shared library functions actually called by a C language program. Therefore, even for multiple processes, each process's first call to the same shared library function will trigger the lazy binding mechanism, which will definitely trigger the code slimming function of the present invention, thus ensuring the sharing of shared libraries. Second, due to the existence of the lazy binding mechanism, whether it is in the form of dynamic linking or dynamic loading, the function address will be calculated through the symbol resolution function in the lazy binding mechanism, which ensures that the code slimming function supports dynamic loading, thus being able to better adapt to various operating environments and requirements.
[0037] 3. The present invention performs code deflation operations on the page cache, avoiding the problem of additional memory overhead that may be brought about by traditional methods. Specifically, the permissions of the program code segment are usually readable and executable but not writable. Therefore, when directly modifying the code segment page in the user state, the copy-on-write (COW) mechanism will be triggered, causing the system to copy a new physical page, thereby privatizing the physical page. Each process will generate an independent memory copy, which will significantly increase memory occupancy. The present invention avoids this problem by directly modifying the page cache in the kernel state, making the memory overhead consistent with the memory occupancy during normal program operation, thereby improving the resource utilization rate of the system. In addition, the present invention also introduces a page-level randomization function. By randomizing the page cache layout of the shared library in physical memory, the security of the system is further enhanced. This randomization mechanism can effectively prevent attackers from using the fixed layout of the shared library for code reuse attacks (such as RET2libc attacks), thereby improving the anti-attack ability of the system.
[0038] In summary, the present invention has significant advantages in the reconstruction and optimization of shared libraries, dynamic function loading, and memory management. Through reconstruction based on function dependency relationships, the present invention optimizes shared libraries in the offline stage, reduces redundant code, and improves loading efficiency and memory utilization. During runtime, the lazy binding mechanism is adopted to dynamically identify the actually used shared library functions, which not only supports code sharing in a multi-process environment but also adapts to dynamic linking and loading requirements, ensuring high efficiency and flexibility. At the same time, the present invention directly modifies the page cache in the kernel state, avoiding the additional memory overhead of traditional methods, and introduces page-level randomization to enhance the security of shared libraries and effectively prevent code reuse attacks. Generally speaking, the present invention effectively improves the running efficiency, memory utilization, and system security of shared libraries. BRIEF DESCRIPTION OF THE DRAWINGS
[0039] Figure 1 This is the overall structure diagram of the present invention.
[0040] Figure 2 This is the workflow diagram of the present invention.
[0041] Figure 3 This is the code slimming effect diagram of the present invention. Detailed implementation manners
[0042] The present invention will be further described in detail below with reference to the accompanying drawings.
[0043] See Figure 2 , a method for reconstructing and dynamically slimming a binary shared library while retaining code reuse attributes, specifically including the following steps:
[0044] Step 1, divide the code partitions of the binary shared library by function to ensure that each code partition contains only a single functional module, and reconstruct the files of the binary shared library based on this to obtain a function dependency file; the specific method is as follows:
[0045] Divide the code partitions of the binary shared library by function to ensure that each code partition contains only a single functional module, and reconstruct the files of the binary shared library based on this to obtain a function dependency file and a pointer information file, the specific method is as follows:
[0046] Through the SVF pointer analysis framework, compiler plugins, and Egalito binary recompilation framework, function dependency analysis, pointer analysis, and reconstruction are performed on the target binary shared library file. First, the shared library source code file is parsed through the intermediate representation (IR) generated by the compiler. The SVF framework performs pointer analysis on the IR at this stage, parses pointer variables and their relationships, and then analyzes the flow of pointers and data transfer. Through pointer analysis, SVF accurately determines which functions are indirectly called through pointers, thereby constructing a function call graph. After obtaining the call graph, using the exported functions of the shared library as the starting point, an empty set is initialized, and the call graph is traversed through breadth-first search. All functions that can be directly or indirectly reached from the exported functions are added to the set until the set no longer changes. Based on this dependency information, the Egalito binary recompilation framework is used to reconstruct the binary shared library file. The reconstructed binary shared library is divided into multiple functional modules, each module corresponding to an independent code partition and aligned with the memory page. Finally, three files will be output: the binary shared library reconstruction file, the function dependency analysis file, and the pointer information file. The content of the function dependency analysis file is that the exported functions of the shared library are used as keywords, and the values corresponding to the keywords are all the shared library functions called by the exported functions in the shared library. The shared library functions obtained in the subsequent lazy binding mechanism are the keywords in the function dependency analysis file - the exported functions. The pointer information file is an auxiliary function of this solution and the information required by the randomization method.
[0047] Step 2, when the user executes the C language program, the custom loader obtains the library functions required by the C language program through the lazy binding mechanism. Since the shared library provides interfaces through exported functions, the loader can combine the function dependency relationship file generated during the reconstruction of the binary shared library. By comparing the library function addresses called by the C language program with the starting offsets of these exported functions, it can be determined which functions and their dependent functions in the shared library are actually called by the main program. The specific method is as follows: In the core function _dl_fixup of the lazy binding mechanism, we introduced additional logic to implement the code slimming function. Specifically, through the return value of the elf_machine_plt_value function, the address of the called shared library function can be obtained. Next, by subtracting this address from the shared library base address result->l_addr, the starting offset of the called function is calculated. This offset value can be compared with the starting offsets of the keyword exported functions recorded in the pre-prepared function dependency file. If the conditions are met, all the information recorded after this keyword can be obtained. Specifically, it is the offset pairs of other shared library functions on which the exported function depends. After these offset information are successfully obtained, the system call function can be called to perform the code slimming operation, removing the unnecessary code in the shared library, thereby achieving function optimization and resource saving.
[0048] In addition, the present invention also introduces the randomization function of the shared library address. During actual operation, in order to ensure that calculations can be performed through the new randomized address when a C language program is running, randomization must be completed before loading the shared library file into physical memory and performing any operations. The timing of this modification happens to be selected in the _dl_map_segments function in the loader. This function is mainly responsible for mapping the shared library file into memory, and at this stage, other operations involving the reading of the.dynamic segment, the shared library relocation table, or the access of symbol references have not been carried out. Therefore, randomization logic is added within the _dl_map_segments function to modify all addresses related to symbol references in the shared library file. After the modification is completed, when the loader accesses the symbol information of the shared library file, the new randomized address modified by us will be used, thus achieving effective randomization of the address during dynamic loading of the shared library. In this way, not only is the smooth execution of code slimming ensured, but also the security of the system is enhanced, avoiding potential security risks caused by static addresses.
[0049] Step 3, manage the page cache content of the process at the operating system kernel layer through the system call module. When a C language program runs, the operating system will create a corresponding process and load the content of the C language program and its dependent shared library files into physical memory according to the execution requirements. Since the copy-on-write (COW) mechanism will be triggered when a user-mode process attempts to modify the content of the shared library file, it is necessary to modify the page table entry permissions corresponding to the page cache in the kernel mode to make it writable to avoid the additional physical memory overhead brought by the COW mechanism. In addition, the system call also implements the randomization of the shared library code segment: when the shared library is loaded for the first time, relevant information related to symbol references is randomly modified, so that when the C language program runs normally, the lazy binding mechanism can calculate the target function position based on the new address. The specific method is as follows: when the customized loader executes, it will pass all the required function offset pair information as parameters to the operating system kernel. Subsequently, the kernel will use this information to slim down the code of the shared library page cache. Since the present invention aims to avoid triggering the copy-on-write (COW) mechanism and instead directly modifies the page cache, it is first necessary to obtain the cache page frame with the corresponding page table entry (PTE) as the input. This process is completed through the pte_page() macro, which can parse the PTE and obtain its corresponding physical page. After obtaining the target page, it is necessary to lock the page first to prevent data inconsistency caused by concurrent access.
[0050] After the page is locked, the kernel needs to modify the page table to allow write operations. Specifically, first update the PTE and mark it as writable, so that kernel functions such as copy_to_user() can safely modify the content of the page. When cleaning and writing to the page cache, all code outside the call scope will be cleared, while the code of the actually called shared library functions and their dependent functions will be retained and written into the page cache. After the modification is completed, the permissions of the page table entry will be restored to the original read-only state to ensure the security and consistency of the memory.
[0051] In addition, when restoring the PTE state, the dirty bit of the PTE also needs to be cleared simultaneously. This is because when modifying the page cache, the PTE will be automatically marked as a dirty page, indicating that the content of the page has changed. The purpose of clearing the dirty bit is to allow the operating system to correctly identify the state of the page and prevent unnecessary write-back operations. At the same time, to ensure that the modification can be correctly perceived by the system, the kernel also needs to flush the TLB (Translation Lookaside Buffer) and related CPU caches to keep the data states of the hardware layer and software layer consistent. Through this series of operations, the present invention successfully realizes code slimming, while avoiding the additional memory overhead caused by copy-on-write, improving the system resource utilization rate, and ensuring the correct operation of the shared library.
[0052] See Figure 1 , a binary shared library reconstruction and dynamic slimming system that retains code reuse attributes, including a binary shared library reconstruction file, a customized loader, and a system call module; wherein:
[0053] Binary shared library reconstruction file: The binary shared library reconstruction file aims to achieve more efficient memory usage and functional modularity by reorganizing and optimizing the binary code of the shared library. By analyzing the function dependency relationships of the shared library, constructing a call graph, and identifying the dependencies between functions. Then, using the method of function clustering, the functions of the shared library are divided into non-overlapping code partitions to ensure that each partition corresponds to a specific functional module. On this basis, metadata information is collected to provide function-level granular support for subsequent code slimming.
[0054] Customized loader module: This module is used to obtain information about the shared library functions actually called by the C language program, which is achieved by combining a customized loader with a lazy binding mechanism. Using the lazy binding mechanism, this solution supports dynamic loading and dynamic linking methods. Regardless of which loading method the shared library uses, when the C language program calls a shared library function, the lazy binding mechanism will be triggered to calculate the actual address of the function, thereby obtaining relevant information.
[0055] System call module: This module is used to modify the page cache information of shared library files in memory with kernel privileges. It modifies the page table entries corresponding to the page cache in physical memory by calling the APIs provided by the operating system kernel, thereby adding write permissions and modifying the page cache content.
[0056] The effects of the present invention can be further verified through the following experiments:
[0057] I. Experimental conditions
[0058] Virtual machine: Ubuntu20.04
[0059] Operating system kernel version: 5.4.273
[0060] Loader version: glibc-2.27
[0061] Shared library file: libFLAC
[0062] Test suite: flac-1.4.0
[0063] II. Experimental settings
[0064] In this experiment, the flac-1.4.0 test suite was tested separately with the code slimming function turned off and on, and the security was detected using the ROPgadget tool.
[0065] III. Experimental process
[0066] The Flac-1.4.0 test suite has a total of 9 test sets. First, after compiling the custom loader, the flac-1.4.0 test suite was used with
[0067] cmake
[0068] -DCMAKE_EXE_LINKER_FLAGS="-Wl,--dynamic-linker= / home / chib igwen / glibc-2.27 / build / elf / ld-linux-x86-64.so.2"
[0069] -DCMAKE_C_FLAGS="-Wl,-rpath= / home / chibigwen / glibc-2.27 / build -Wl,-rpath= / home / chibigwen / glibc-2.27 / build / math-z lazy" -DCMAKE_CXX_FLAGS="-Wl,-rpath= / home / chibigwen / glibc-2.27 / build -Wl,-rpath= / home / chibigwen / glibc-2.27 / build / math-z lazy"..
[0070] This instruction is recompiled. After compilation, this test suite will use the loader customized by the present invention. Then, in the directory / home / chibigwen / Desktop / flac-1.4.0 / build / src / libFLAC, the reconstructed shared library file will be directly replaced with libFLAC.so.12.0.0 in this directory. The directory of the dependent files is written into the operating system kernel. Finally, the operating system kernel is recompiled and then replaced with the kernel customized by the present invention.
[0071] Then the testing can begin. Since the test suite used in this experiment belongs to the type that highly frequently calls shared library functions. Therefore, the data will vary greatly. The test suites used this time are: test_libflac, decode_example, test_grabbag, test_seeking, test_flac, test_compression, test_replaygain, test_streams, test_metaflac. Since there are many parameters in the execution instructions of some test suites, the following instructions are used in this experiment to execute the test suites:
[0072] cd flac-1.4.0 / build / test
[0073] export FLAC__TEST_LEVEL=1
[0074] export ECHO_C=\c
[0075] sh.. / .. / test / test_libFLAC.sh
[0076] By changing the name of the.sh file in the last instruction, other test suites can be run.
[0077] To verify the actual effect of the present invention, we added special processing logic to the kernel, which can trigger all pages of the target shared library code segment. After modifying the content of the page cache, the system will output the modified page content in binary form to a text file. After the program execution ends, copy the content of this file to the reconstructed shared library file, so that its code segment only contains all the function contents actually called during program operation, and the pages of the remaining unused functions have been cleared, which indicates that the code slimming function has been successfully achieved. To ensure the accuracy of the results, we also designed a more rigorous verification process: collect the offset information of the shared library functions called by the program and all their dependent functions in the loader, and write this information to a text file. Subsequently, with the help of a dedicated script, we zero out the functions not within these offset ranges. By repeating this complete process in each test case, we can generate two slimmed-down versions of the shared library, thus ensuring the accuracy and reliability of the experimental results.
[0078] IV. Experimental Analysis
[0079]
[0080] test_libflac: Reduction in all gadgets: 13.6%, reduction in code: 23.5%, reduction in functions: 7%, failure to build a ROP chain.
[0081] decode_example: Reduction in all gadgets: 74.5%, reduction in code: 79.9%, reduction in functions: 71.8%, failure to build a ROP chain.
[0082] test_grabbag: Reduction in all gadgets: 92.0%, reduction in code: 96.0%, reduction in functions: 89.8%, failure to build a ROP chain.
[0083] test_seeking: Reduction in all gadgets: 22.9%, reduction in code: 31.1%, reduction in functions: 37.9%, failure to build a ROP chain.
[0084] test_flac: Reduction in all gadgets: 14.5%, reduction in code: 23.7%, reduction in functions: 22.1%, failure to build a ROP chain.
[0085] test_compression: Reduction in all gadgets: 24.8%, reduction in code: 27.8%, reduction in functions: 34.5%, failure to build a ROP chain.
[0086] test_replaygain: Reduction in all gadgets: 23.2%, reduction in code: 31.6%, reduction in functions: 34.7%, failed to build ROP chain.
[0087] test_streams: Reduction in all gadgets: 31.0%, reduction in code: 34.7%, reduction in functions: 39.8%, failed to build ROP chain.
[0088] test_metaflac: Reduction in all gadgets: 23.3%, reduction in code: 32.3%, reduction in functions: 29.9%, failed to build ROP chain.
[0089] The above content and the table are the final test results. Figure 3 Here is the effect diagram:
[0090] When explaining each item in the table, first look at the second column "Number of all gadgets". In a Return-Oriented Programming (ROP) attack, an attacker can use these gadgets to build an ROP chain to hijack the execution flow of a C program. Therefore, the fewer the number of gadgets, the fewer ROP fragments an attacker can use, thus reducing the risk of ROP attacks. Therefore, reducing the number of gadgets is an important goal during code slimming.
[0091] However, it should be noted that the test suite used in this experiment mainly focuses on the functional testing of the libFLAC shared library. Therefore, its test cases are relatively single, resulting in the code slimming effect being extremely manifested in some scenarios. For example, on the Linux system, the most commonly used shared library is glibc. After testing it, it is found that 95% of the functions in the glibc code are not actually called under normal use. In this case, the code slimming effect is very significant. After removing the unused parts, the number of available gadgets can be greatly reduced. However, if the target shared library needs to use more than 95% of its functions during program operation, then the code slimming effect will be relatively poor. To solve this problem, the present invention additionally introduces the function of shared library address randomization. Even if the code slimming effect is not good, this randomization mechanism can still effectively resist ROP attacks, thus providing double protection.
[0092] The code size refers to the size of the code segment of the binary file of the shared library. The code reduction amount indicates how much content of the shared library file has been cleared. The number of functions refers to the normal number of functions, and the function reduction amount represents how many functions are not used and removed after code slimming. In the first column of the table, the data in the "reconstructed library" row represents the shared library data without using the code slimming function. From the ratio summarized later, it can be seen that the effect of code slimming is closely related to the number of functions actually called. For example, in the two test sets of decode_example and test_grabbag, the size ratio of the shared library after code slimming is approximately between 70% and 90%, indicating that the code slimming effect is relatively obvious. On the contrary, if code slimming is not performed, the number of gadgets that attackers can utilize will be large. For example, in the libFLAC shared library, the initial number of gadgets is as high as 11,948.
[0093] In addition, Figure 3 shows the changes in the shared library after implementing the code slimming function. It can be seen that after code slimming, the functions that are not called and their dependent codes are cleared, resulting in a significant reduction in the number of exploitable gadgets in the shared library, thereby reducing the attack surface and improving the security of the program.
Claims
1. A method for reconstructing and dynamically slimming a binary shared library while retaining code reuse attributes, characterized in that Specifically, it includes the following steps: Step 1: Partition the code of the binary shared library through function division to ensure that each code partition contains only a single functional module, and reconstruct the files of the binary shared library based on this to obtain a function dependency file and a pointer information file. The content of the function dependency file is the exported functions of the binary shared library and their dependent function information; Using the exported functions of the binary shared library as keywords, the values corresponding to the keywords are all the binary shared library functions called by the exported functions in the binary shared library; The pointer information file is the information required by the randomization method; Step 2: Based on the files of the binary shared library reconstructed in Step 1, start code slimming: When the user executes a C language program, the customized loader obtains the binary shared library functions required by the C language program through the lazy binding mechanism, and combines with the function dependency file obtained during the process of reconstructing the files of the binary shared library in Step 1. By comparing the binary shared library functions called by the C language program with the content of the function dependency file obtained in Step 1, it is determined that the C language program actually calls the exported functions and their dependent functions in the binary shared library, and the code slimming function is started; Step 3: Perform dynamic slimming of the files of the binary shared library: After starting the code slimming function, manage the page cache content at the operating system kernel layer through the system call module. The loader passes the information of the exported functions and their dependent functions of the binary shared library obtained as parameters of the system call function into the kernel; The system call function uses the information of the exported functions and their dependent functions of the binary shared library to write the relevant content into the page cache as needed to achieve code slimming; Since the user-mode process will trigger the copy-on-write mechanism when modifying the page cache of the shared library file, it is necessary to modify the page table entry permissions of the corresponding pages in the page cache with the kernel-mode identity to make it writable, thus avoiding the additional physical memory overhead brought by copy-on-write; In addition, when the system call module first loads the binary shared library, it randomly modifies the relevant information related to symbol references, so that when the C language program runs normally, the lazy binding mechanism can calculate the target function position according to the new address, realizing the randomization of the shared library code segment.
2. The method for reconstructing and dynamically slimming a binary shared library with code reuse attribute retention according to claim 1, characterized in that Each line of the function dependency file described in Step 1 uses the starting address of the exported function of the binary shared library as the keyword, followed by the offset pairs of all the binary shared library functions depended on by this exported function; The content of the pointer information file includes the base address, target address, offset, pointer size, and specific value of the pointer, and is stored in text form.
3. A method for reconstructing and dynamically slimming a binary shared library with code reuse property retention, according to claim 1 or 2, characterized in that The specific method of Step 1 is as follows: Through offline components including the SVF pointer analysis framework, compiler plugin, and Egalito binary recompilation framework, perform function dependency analysis, pointer analysis, and reconstruction on the files of the target binary shared library; Step 1.1: The source code file of the binary shared library is converted into an intermediate representation IR by the compiler; Then, the compiler plugin intervenes, uses the SVF pointer analysis framework to obtain the call relationships of each function in the shared library file, and stores these relationships using the adjacency matrix data structure to obtain a function call graph; Step 1.2, after obtaining the call graph, initialize an empty set with the exported functions of the binary shared library as the starting point, and traverse the call graph through breadth-first search. Add all functions that can be directly or indirectly reached from the exported functions to the set until the set no longer changes, i.e., the construction of function clustering is completed; use the Egalito binary recompilation framework to intercept address allocation, reallocate new addresses for each function according to the information of function clustering, and ensure memory alignment at the same time to reconstruct the binary shared library file. The reconstructed binary shared library is divided into multiple functional modules, each module corresponding to an independent code partition and aligned with the memory page; Finally, output the reconstructed binary shared library file, the function dependency analysis file, and the pointer information file.
4. A method for reconstructing and dynamically slimming a binary shared library with code reuse property retention, according to claim 3, characterized in that The content of the function dependency analysis file uses the exported functions of the binary shared library as keywords, and the value corresponding to the keyword is all the binary shared library functions called by the exported function in the binary shared library; The pointer information file is the information required by the randomization method.
5. A method for reconstructing and dynamically slimming a binary shared library while retaining code reuse attributes according to claim 1, characterized in that The specific method of step 2 is as follows: When the user executes the C language program, the custom loader obtains the binary shared library functions required by the C language program through the lazy binding mechanism, that is, when the C language program first calls a certain function in the binary shared library, the lazy binding mechanism is triggered. The lazy binding mechanism of the loader calculates the real address of the shared library function and fills this address into the GOT table of the C language program; therefore, not all binary shared library functions will be resolved immediately when the program starts, but the loader dynamically looks up the actual address of the function at the first call and obtains the exported functions of the binary shared library actually called by the C language program including its function name and start address in real time; subsequently, compare the exported functions of the called binary shared library with the content of the function dependency relationship file obtained in step 1 to find the corresponding exported functions of the binary shared library and all functions they depend on, and start the code slimming function.
6. A method for reconstructing and dynamically slimming a binary shared library with code reuse property retention, as claimed in claim 1, wherein The specific method of step 3 is as follows: Add the functional logic code for obtaining and comparing dependency information inside the _dl_lookup_symbol_x function in the lazy binding _dl_fixup of the custom loader, that is, compare with the function dependency relationship file obtained in step 1 according to the information of the called binary shared library function, obtain the offset information of all dependent functions, and pass the offset information of all dependent functions as parameters to the operating system call for code slimming to be executed in the operating system kernel; When the C language program accesses the real address of the binary shared library function calculated by the lazy binding mechanism of the loader during the execution of the C language program in step 2, the control right is handed over to the operating system kernel; the kernel first checks whether the memory page where the address is located has been mapped to the physical address. If so, no page fault is triggered and the program executes normally; if not, it means that this page is accessed for the first time, then the operating system kernel triggers a page fault exception and triggers page swapping; before triggering page swapping, the operating system kernel judges whether this page swapping is legal. If it is legal, the page swapping process starts; During the paging process, the operating system kernel first checks whether the page is in the page cache. If the cache is hit, the data in the cache is directly used; otherwise, it means that there is no corresponding page in the existing page cache, and the file content needs to be found from the disk, and the file content is pasted into the page cache, the page content is loaded from the disk into physical memory, and the page table entry is updated; After the kernel completes paging, it first grants write permissions to the relevant page table entries and synchronizes the granting of write permissions to the relevant page table entries to the page cache so that subsequent modifications will not trigger the copy-on-write mechanism; then it formally performs code slimming. First, it clears all the page cache contents of the binary shared library, and then based on the starting offset of the obtained dependent functions, it obtains the page numbers of the exported functions of the binary shared library called in step 2 and the pages where their dependent functions are located. Then, according to the page numbers, the exported functions of the binary shared library and their dependent functions are written to the corresponding positions in the page cache in sequence according to the offset values; finally, only the exported functions of the binary shared library required by the C language program and their dependent functions are retained in memory, and the rest of the useless code is cleared, realizing the slimming of the binary shared library code; finally, the kernel restores the original permissions of the page table entries to ensure the normal execution of the program.
7. A binary shared library reconstruction and dynamic slimming system that retains code reuse attributes, characterized in that It includes a binary shared library reconstruction file, a customized loader module, and a system call module; The binary shared library reconstruction file is used for step 1. By reorganizing and optimizing the binary code of the shared library, it realizes efficient memory usage and functional modularization; by analyzing the function dependency relationship of the shared library, it constructs a call graph and identifies the dependencies between functions; Then, using the method of function clustering, the functions of the shared library are divided into non-overlapping code partitions to ensure that each partition corresponds to a specific functional module; on this basis, metadata information is collected to provide function-level granularity support for subsequent code slimming; The customized loader module is used for step 2. By combining the customized loader with the lazy binding mechanism, it realizes obtaining the information of the shared library functions actually called by the C language program; using the lazy binding mechanism, it supports the shared library in the dynamic loading and dynamic linking methods. No matter which loading method the shared library uses, when the C language program calls the shared library function, the lazy binding mechanism will be triggered to calculate the actual address of the function, so as to obtain the exported functions of the shared library actually called by the C language program including their function names and starting addresses, and compare the exported functions of the shared library called with the content of the function dependency file pre-obtained in step 1 to find the corresponding exported functions of the shared library and all the functions they depend on, and start the code slimming function; The system call module is used for step 3. It modifies the page cache information of the shared library file in memory in the kernel state, and modifies the page table entries corresponding to the page cache in physical memory by calling the operating system kernel, so as to add write permissions and modify the page cache content.
8. A binary shared library reconstruction and dynamic slimming device that retains code reuse attributes, characterized in that, It includes: A memory for storing a computer program; A processor for executing the computer program to perform the binary shared library reconstruction and dynamic slimming method according to any one of claims 1 to 6.
9. A computer-readable storage medium storing a computer program, characterized in that, When the computer program is executed by a processor, it can implement the reconstruction and dynamic slimming of binary shared libraries based on the binary shared library reconstruction and dynamic slimming method described above.