A modular approach for binary programs
By constructing a functional dependency graph and combining it with a community detection algorithm, and utilizing a local move algorithm based on similar neighbor movement and modularity gain, the problems of information loss and low time efficiency in binary program modularization are solved, achieving more efficient modularization and better analysis results.
Patent Information
- Application Number
- CN202210508164.X
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2022-04-27
- Publication Date
- 2025-10-28
- Estimated Expiration
- 2042-04-27
AI Technical Summary
Existing binary program modularization methods suffer from information loss and low time efficiency when processing large-scale programs, making it difficult to effectively extract information from programs and efficiently process large-scale programs.
By constructing a functional dependency graph, utilizing local move algorithms based on similar neighbor movement and modularity gain, and combining function calls, data references, and local code dependencies, the community detection approach is adopted for modularization, extracting functional dependencies and dividing the code into modules.
It improves the time efficiency of binary program modularization, outperforming existing methods, and achieves better modularization results and higher analysis efficiency.
Smart Images

Figure CN115167916B_ABST
Abstract
Description
Technical Field
[0001] This invention belongs to the field of modular analysis technology, specifically relating to a modular method for binary programs. Background Technology
[0002] As software system functions become more diverse, system complexity and function size also increase. In practical applications, researchers often cannot obtain the program's source code and can only analyze binary programs, especially large-scale binary programs (containing tens of thousands of functions), which takes a considerable amount of time and severely impacts analysis efficiency. Software modularization refers to a software analysis method that clusters program elements (files, packages, functions, methods, etc.) to obtain the software module structure. Software modularization technology divides the program into relatively independent modules. A module is a set of functions that perform a specific function, characterized by "high cohesion and low coupling." Analyzing each module separately can reduce analysis complexity and improve the analysis efficiency of complex binary programs. Furthermore, researchers only need to analyze specific functional modules to search for and locate 1-day vulnerabilities.
[0003] Currently, there are many methods for modularizing source code, and a small amount of work on binary program modularization. Compared with source code modularization, binary program modularization has two main problems: information loss during compilation and time performance issues when processing large-scale binary executables. Current binary program modularization work, such as BCD (Browser-Coordination Diagram), uses graph clustering to divide binary code into components, essentially clustering methods within a class in a C++ program together. This method loses some important information during graph construction, and the clustering algorithm has low time efficiency. To achieve more effective binary program modularization, two challenges arise: first, how to effectively extract the information contained in the binary program; and second, how to efficiently process large-scale binary programs.
[0004] Researchers have proposed various modularization methods that attempt to classify more similar or closely related artifacts into modules. From the perspective of clustering algorithms, these methods are mainly divided into aggregation-based and search-based methods. Aggregation algorithms require maintaining a similarity matrix representing the similarity between clusters, and this matrix needs to be recalculated in each iteration. If the number of clusters is large, this similarity matrix will be very large, and calculating the similarity matrix is also very time-consuming. In the analysis of search-based algorithms, the clustering problem is regarded as a search problem, and hill-climbing algorithms and genetic algorithms are commonly used to implement clustering. Search-based algorithms solve a problem by exhaustively exploring some or all cases in the solution space. In the solution process, only considering some cases may yield a local optimum; to obtain the global optimum, all cases must be considered, and the entire solution space must be searched. However, processing large-scale binary programs is very time-consuming, which is impractical for time-sensitive tasks. Therefore, how to improve the time performance of binary program modularization is an urgent problem to be solved. Summary of the Invention
[0005] To address the shortcomings and problems of current binary program modularization methods, such as time consumption and insufficient performance when handling large-scale complex binary programs, this invention provides a modularization method for binary programs.
[0006] The solution adopted by this invention to solve its technical problem is: a modular method for binary programs, comprising the following steps:
[0007] Step 1: Disassemble the binary function and extract the function dependencies to construct a function dependency graph, where nodes represent functions and edges represent the dependencies between functions.
[0008] Step 2: Divide the function dependency graph into modules containing various function sets, including the following steps:
[0009] S1. Similar Neighbor Movement: Input the node set V, the function edge dependency set E, and the similarity threshold w. Treat each node as an independent module, merge nodes based on similar neighbor movement, and calculate the similarity value SV between each node and all its neighbors using Jaccard distance during the similar neighbor movement process. ij This yields the set of similarity values (SVs) between the node and all its neighboring nodes.
[0010]
[0011] In the formula: N(i) and N(j) represent the neighbors of node i and node j, respectively;
[0012] Select the largest SV from SVs; if the largest SV value is higher than the similarity threshold w, move the node to the module of the neighbor node with the largest SV value; otherwise, the node remains in its original module; output the communities of each node.
[0013] S2. Local movement based on modularity gain: input function node set V, function dependency edge set E, and the community where the node is located at this time;
[0014] For each function node, firstly, the module where the node is located is initialized as the best module and the module degree gain is initialized to 0. Then, the module degree gain of moving the node to the modules where all its neighboring nodes are located is calculated and recorded, and the module with the largest module degree gain and the associated module is selected.
[0015] If the maximum modularity gain is greater than 0, move the node to the relevant module; otherwise, leave it in the original module. Iterate until no node has a modularity gain greater than 0 after the local move. Then output the communities of each node generated after the local move based on the modularity gain.
[0016] S3, Module Combination: The modules generated after local movement based on modularity gain are merged into a new node. The dependencies between functions within a module are merged into self-loops of the new node, thus constructing a new network. The nodes in the new network are modules based on local movement based on modularity gain, and the dependencies between the new nodes are the dependencies between the corresponding modules of the new nodes.
[0017] The modularization method for binary programs described above includes function call dependencies, data reference dependencies, and code local dependencies, where function call dependencies include direct call dependencies and co-reference dependencies.
[0018] The modular approach for binary programs described above treats strings as data for data reference dependencies. To obtain the data referenced by each function, it iterates through each instruction of the function and checks if it cross-references the offset address of the string stored in the .rodata segment. It then retrieves all such offset addresses and maps them to the function. For each function, the mapping relationship is expressed as: Φ: f→D, D= <D1,...,D m >, where D i This represents the i-th string accessed by function f; after iterating through all functions...
[0019] If functions A and B access the same data, an edge is created from function A to function B. A large number of shared data references between functions A and B means they are more likely to belong to the same module. The edge weight for data reference dependencies is equivalent to the number of times the data is referenced.
[0020]
[0021] In the formula: It is the data reference dependency weight of function i and function j; y d It refers to the number of times the same data is referenced; E d It is a set of data reference dependency edges.
[0022] The modular approach for binary programs described above, regarding code locality dependencies, first sorts all functions by address, then constructs an edge with a weight of 1 between any two adjacent functions; sorting the functions by address yields a set f1, f2, ..., f n The weights of the constructed code locality dependency edges are:
[0023]
[0024] In the formula: W l ij It is the data reference dependency weight between function i and function j.
[0025] The modular approach for binary programs described above, after extracting all function dependencies, constructs a weighted function dependency graph G = (V, E, W) when building the function dependency graph, taking into account the possible edges between different modules. Here, V is the set of functions in the binary program, E represents the dependencies between functions, and the weights are a combination of the three dependency relationships.
[0026]
[0027] In the formula: W ij It is the sum of the dependency weights of functions i and j; the parameters α, β, and γ represent the contributions of function call dependency, data reference dependency, and code local dependency, respectively; α + β + γ = 1.
[0028] The beneficial effects of this invention are as follows: By analyzing binary programs, this invention extracts four types of functional dependencies to discover more dependencies within modules, thus improving binary program modularization. Furthermore, considering the characteristics of binary programs, it incorporates a community detection algorithm and explores higher-order features between vertices, determined through the shared neighbor structure of vertices. Then, an improved method is used for binary program modularization. Experiments show that, in terms of time efficiency, the method of this invention consumes only 7.95% of FCA and 21.51% of BCD, outperforming the existing best modularization methods FCA and BCD, indicating that it achieves better modularization results and higher efficiency. Attached Figure Description
[0029] Figure 1 This is a flowchart of the binary program modularization of the present invention.
[0030] Figure 2 A modular process flowchart for existing programs.
[0031] Figure 3 This is a graph of functional dependencies.
[0032] Figure 4 This is a diagram illustrating the movement of similar neighbors.
[0033] Figure 5 This is a schematic diagram of local movement based on modularity.
[0034] Figure 6 This is a schematic diagram of the module combination.
[0035] Figure 7 The results of the V-measure are shown for each parameter.
[0036] Figure 8 The results of V-measure when different similarity thresholds are selected. Detailed Implementation
[0037] Program modularization involves dividing a program into modules to maximize internal connectivity (high cohesion) and minimize inter-module connectivity (low coupling). Figure 1 This demonstrates the modularization process of the program. The input to the clustering algorithm is an artifact dependency graph constructed from the program code. Nodes in the graph represent artifacts (e.g., classes, methods, files, functions, etc.), and connections represent relationships between artifacts (call dependencies, inheritance dependencies, semantic dependencies, etc.). Researchers have proposed various modularization methods that attempt to classify artifacts that are more similar or more closely related to each other into modules. From the perspective of clustering algorithms, these methods are mainly divided into aggregation-based and search-based methods.
[0038] The modular approach based on aggregation first initializes each workpiece as a separate cluster, then iteratively merges the two most similar clusters and decrements the cluster size by 1. The clustering process is as follows: First, the workpieces in the program and their features are identified, and each workpiece is represented as a feature vector. Next, a similarity measurement method is selected (e.g., the Jaccard similarity criterion or the Euclidean distance criterion), and an n*n similarity matrix is calculated based on the feature vectors to represent the similarity between each pair of workpieces. The clustering algorithm iteratively merges entities with the highest similarity based on the similarity matrix.
[0039] Single-link, fully-link, and average-link are classic aggregation algorithms. Saeed et al. proposed a Combined Algorithm (CA) for syntactic clustering. This algorithm first initializes each artifact as a separate module and uses a binary data table to represent the relationships between modules and features. It then calculates the similarity between modules using the Jaccard similarity measure. Next, it merges the two modules with the highest similarity into a new module and recalculates the similarity between the merged modules. In the CA algorithm, the feature vector of the new module after merging the two most similar modules is the XOR operation of the feature vectors of the two old modules. Maqbool et al. proposed a modular algorithm called Weighted Combined Algorithm (WCA). This algorithm uses a weighted version of Jaccard to calculate the similarity between modules, considers the access patterns of artifacts within a module, and maintains information about the number of artifacts accessing a certain feature within a module. The LIMBO algorithm utilizes the concepts of information theory and entropy to perform clustering based on minimizing information loss during the modularization process. To overcome the shortcomings of a single similarity criterion, Naseem et al. proposed the idea of cooperative clustering, calculating the similarity between modules based on multiple similarity criteria.
[0040] Search-based algorithms treat clustering as an optimization problem, using heuristic search to find approximate optimal solutions. The search process is guided and evaluated by a Modularization Quality (MQ) objective function, which measures the suitability of the solution. Mitchell et al. proposed the Bunch tool to solve software clustering problems. This tool integrates a Genetic Algorithm (GA) and a Hill Climbing (HC) algorithm, where the GA uses real-valued encoding to represent the solution, and the resulting search space is O(n^2). n(n is the number of jobs). Bunch can produce good partitioning results, but as the number of program jobs increases, the search space increases exponentially, making it unsuitable for large programs. To reduce the huge search space faced by the inheritance algorithm in Bunch, Parsa et al. proposed the DAGC method for program modularization. DAGC uses a genetic algorithm to search the solution space, minimizing the search space by restricting the encoding operations. During the encoding process, each chromosome is encoded by the arrangement of graph nodes, and the search space of this algorithm is O(n!). Praditwong et al. proposed the GCA and GCE algorithms, both of which are based on genetic algorithms and use different encoding modes to cluster software modules, while using corresponding selection, crossover, and mutation operators to obtain the optimal solution of the algorithm. Later, Praditwong et al. designed two genetically based, multi-objective algorithms, MCA and ECA, for program module clustering, incorporating different objectives such as the sum of edges within modules (cohesion), the sum of edges between modules (coupling), the number of modules, the number of single-point modules, and the uniformity of the number of jobs within a module.
[0041] However, aggregation algorithms require maintaining a similarity matrix representing the similarity between clusters, and this matrix needs to be recalculated in each iteration. If the number of clusters is large, this similarity matrix will be very large, and calculating the similarity matrix is also very time-consuming. Search-based algorithms solve a problem by exhaustively searching some or all cases in the problem's solution space. Considering only some cases in the solution process may yield a locally optimal solution; to obtain the globally optimal solution, all cases must be considered, and the entire solution space must be searched. This is very time-consuming for large-scale binary programs, which is impractical for time-sensitive tasks.
[0042] To better modularize binary programs, this paper designs a binary program modularization model called BinMod (Binary Modularization).
[0043] To address the first challenge, analysis of binary programs reveals that while much structural information is lost during compilation, useful information is still retained, aiding in the identification of program modules. This paper proposes four key properties that preserve information about the original program modules throughout the compilation process, using this information to construct a function dependency graph.
[0044] The second challenge is to modularize the software using the community detection concept from complex network theory. Research has found that software systems represent an important class of complex networks. Complex networks possess the characteristics of being scale-free, small-world, and having a "community structure." The "community structure" refers to the structural feature of "tightly connected nodes within the same community and sparsely connected nodes between different communities." The "high cohesion, low coupling" modules of a program are very similar to the "communities" of complex networks. With the maturation of community detection, community detection in large-scale networks, as an important branch, has received widespread attention and research. Therefore, this paper borrows the concept of community detection to modularize binary programs to address their time performance issues. The invention is further illustrated below with reference to the accompanying drawings and embodiments.
[0045] Example 1: A modular approach for binary programs, comprising the following steps:
[0046] Step 1: Disassemble the binary function and extract the function dependencies to construct a function dependency graph, where nodes represent functions and edges represent the dependencies between functions.
[0047] Step 2: Divide the function dependency graph into a set of modules containing the corresponding function sets. This mainly includes three steps: similar neighbor movement, local movement based on module degree gain, and module combination.
[0048] 1. Moving similar neighbors,
[0049] The input nodes are V, the function edge dependencies are E, and the similarity threshold is w.
[0050] Each node is treated as an independent module. Nodes are merged based on similar neighbor movement, and during the similar neighbor movement process, the similarity value SV between each node and all its neighboring nodes is calculated using Jaccard distance. ij ,
[0051]
[0052] In the formula: N(i) and N(j) represent the neighbors of node i and node j, respectively;
[0053] Obtain the set of similarity values SVs between the node and all its neighboring nodes, and select the largest SV from SVs;
[0054] If the maximum SV value is higher than the similarity threshold w, then move the node to the module of the neighbor node with the maximum SV value; otherwise, the node remains in its original module; output the communities of each node.
[0055] 2. Local shift based on module gain
[0056] The input consists of the set of function nodes V, the set of function-dependent edges E, and the communities where the nodes currently reside.
[0057] For each function node, firstly, the module where the node is located is initialized as the best module and the module degree gain ΔQ is initialized to 0. Then, the ΔQ of moving the node to the modules where all its neighboring nodes are located is calculated and recorded, and the largest ΔQ and the associated module are selected.
[0058] If the maximum ΔQ is greater than 0, move the node to the relevant module; otherwise, leave it in the original module. This process is performed iteratively until no module degree gain is greater than 0 after the local move of any node; output the communities of each node generated after the local move based on the module degree gain.
[0059] 3. Module combination
[0060] The modules generated after local movement based on modularity gain are merged into a new node, and the dependencies between functions within the module are merged into self-loops of the new node. The dependencies between the new nodes are the dependencies between the corresponding modules of the new node. In this stage, a new network is constructed, in which the nodes are modules based on local movement based on modularity gain, and the edges between nodes are the sum of the edge weights between the corresponding modules. Then, each new node is initialized in a new module.
[0061] Example 2: This example provides a modular approach for binary programs, such as... Figure 1 As shown, this method mainly includes two processes: function dependency graph construction and modularization.
[0062] Given a binary file, we first disassemble it and extract the function dependencies, constructing a function dependency graph. In the graph, nodes represent functions, and edges represent the dependencies between functions. The modularization process divides the function dependency graph into a set of modules containing corresponding sets of functions. A module is a set of functions that perform a specific function and has the characteristics of "high cohesion and low coupling".
[0063] The first part is the construction of the function dependency graph, which involves extracting the dependencies between functions in the binary program and constructing the function dependency graph. For example... Figure 3 As shown, there are four types of function dependencies: direct call dependency, co-reference dependency, data reference dependency, and local code dependency.
[0064] The second part is modularization. This process uses a modularization algorithm to divide the functional dependency graph into modules, including three steps: similar neighbor movement, local movement based on modularity gain, and module combination. The specific implementation details of each process are described below.
[0065] 2.1 Construction of Functional Dependency Graph
[0066] Although much structural information is lost during compilation, the binary program still retains useful information that helps identify modules within the program. By analyzing the binary program, four key attributes were identified that preserve information about the original program modules throughout the compilation process, and this information was used to construct a function dependency graph. For example... Figure 3 As shown, four types of function dependencies between function A and function B are illustrated: direct call dependency, coreference dependency (extracted from the original direct call dependency), data reference dependency, and code local dependency.
[0067] Finally, a weighted undirected graph is constructed using all the dependencies. The edges between function nodes in the graph are weighted and undirected, with the weights being a combination of the parameters and the weights of various dependent edges.
[0068] 2.1.1 Function call dependency
[0069] Function call dependencies include direct call dependencies and cross-reference dependencies. When function A directly calls function B, the two functions are structurally related. When a set of functions calls each other more often than they call functions not in that set, this set of functions is more likely to reside in the same module. If function A and function B are frequently called together, they have a cross-reference dependency and are very likely to reside in the same module (for example, the utility module contains the memset and memcpy functions, which are frequently called together).
[0070] If function A directly calls function B, function B directly calls function A, or a function calls both function A and function B, then an edge exists between function A and function B. The number of calls indicates the weight between the two functions. A higher number of calls indicates a stronger structural relationship between the two functions. The function call dependency weight equals the number of calls, expressed as:
[0071]
[0072] in It is the function call dependency weight of function i and function j; y c It is the number of function call dependencies; E c It is a set of function call dependency edges.
[0073] 2.1.2 Data Reference Dependency
[0074] Functions that operate on the same data may be structure-dependent because the semantics of the function relate to the data operations. In this embodiment, strings are used as data. To obtain the data referenced by each function, each instruction of the function is traversed, and it is determined whether it cross-references the offset address of the string stored in the .rodata segment. All such offset addresses are obtained and mapped to the function. For each function, the mapping relationship is expressed as: Φ:f→D,D= <D1,...,D m >, where D i This represents the i-th string accessed by function f. After traversing all functions, if function A and function B access the same data (offset), an edge is established from function A to function B. A large number of shared data references between functions A and B means they are more likely to belong to the same module. The edge weight for data reference dependencies is equivalent to the number of times the data is referenced, expressed as:
[0075]
[0076] in It is the data reference dependency weight of function i and function j; y d It refers to the number of times the same data is referenced; E d It is a set of data reference dependency edges.
[0077] 2.1.3 Local Code Dependencies
[0078] Typically, compilers group functions from the same file or folder together during compilation, meaning these functions will have similar addresses in the final compiled binary. Therefore, we consider locality of reference (assuming no code obfuscation). First, we sort all functions by address, then we create an edge with a weight of 1 between adjacent functions. Let's assume the set of functions sorted by address is f1, f2, ..., f... n The weights of the constructed code locality dependency edges can be represented as:
[0079]
[0080] 2.1.4 Functional Dependency Graph
[0081] After extracting all functional dependencies, a functional dependency graph is constructed. Since edges may also exist between different modules, a weighted functional dependency graph is built. Functions within the same module have more interactions than functions between modules, and therefore have higher weights, making them more likely to be grouped together during module partitioning. Therefore, the functional dependency graph is weighted to highlight functional dependencies within the same module. The functional dependency graph is represented as G = (V, E, W), where V is the set of functions in the binary program, and E represents the dependencies between functions. The weight is a combination of the three types of dependencies mentioned above, expressed as:
[0082]
[0083] Among them W ij It is the sum of the dependency weights of functions i and j; the parameters α, β, and γ represent the contributions of function call dependencies (direct call dependencies and co-reference dependencies), data reference dependencies, and code local dependencies, respectively; α + β + γ = 1.
[0084] 2.2 Binary Program Modularization
[0085] To improve the effectiveness of modularization, higher-order features between vertices were explored, namely, shared neighbor features between nodes. For example, for nodes A, B, and C, if node C is a neighbor of node A and node B, then node C is a shared neighbor of nodes A and B.
[0086] like Figure 4 As shown, nodes 1, 2, 3, and 4 are shared neighbors of nodes 5 and 6. Based on the relatively weak direct connection strength between nodes (nodes 5 and 6 only have an edge with a weight of 1), their final interaction strength is determined by analyzing their shared neighbor structure (shared neighbor nodes 1, 2, 3, and 4). (Compared to other nodes, nodes 5 and 6 have a higher interaction strength). The general idea of higher-order structures can be explained as nodes with more shared neighbors are more likely to be similar. The method in this paper includes three steps: (1) similar neighbor movement, (2) local movement based on modularity gain, and (3) module combination.
[0087] The following is a code example of the overall flow of the binary program modularization.
[0088]
[0089] During the module partitioning process, the sum of module degrees (best_q) of each module is iteratively updated, and this value is initialized to -1 (line 2). First, higher-order characteristics of nodes are considered, and nodes are merged using similar neighbor moves (line 3). Then, local moves and module combinations based on module degree gain are iteratively executed (lines 4-10) until best_q no longer increases, at which point the maximum module degree is obtained. In each iteration, best_q is calculated after each local move (lines 5-6). If best_q no longer increases, the iteration stops (lines 7-8); otherwise, a new network is constructed, the maximum module degree value is updated (lines 9-10), and node moves continue.
[0090] 2.2.1 Moving Similar Neighbors
[0091] To capture higher-order relationships between vertices, i.e., relationships between shared neighbors, similar neighbor movement is performed first during the modularization process, such as... Figure 5 As shown in the figure, the numbers on the lines represent the weight values between nodes. It can be seen from the figure that the connection weight between node 6 and node 7 is greater than that between node 6 and node 5. However, since node 6 and node 5 have many common neighbors: node 1, node 2, node 3 and node 4, node 5 and node 6 are more likely to be in the same module. Therefore, node 5 and node 6 should be merged into one module.
[0092] The specific similar neighbor moving algorithm is shown below. The input of the algorithm is the set of nodes V, the set of functional edge dependencies E, and the similarity threshold ω. The output is the communities of each node.
[0093]
[0094] First, treat each node as an independent module (line 2).
[0095] Then, nodes are merged based on similar neighbor movement (lines 3-12). During the similar neighbor movement process, for each node, the Jaccard distance (SV) is used to calculate its similarity value with all its neighboring nodes, and the largest SV is selected from these SVs (lines 6-10). If the largest SV is higher than the similarity threshold ω, the node is moved to the module containing the neighbor with the largest SV value (lines 11-12); otherwise, the node remains in its original module. The expression for calculating SV is:
[0096]
[0097] In the formula: N(i) and N(j) represent the neighbors of node i and node j, respectively.
[0098] 2.2.2 Local Shift Based on Modularity Gain
[0099] The modularity Q∈[-1,1] of a network is an indicator that measures the difference between the structural distribution of network nodes under completely random conditions and the community structural distribution obtained from actual network detection. Specifically, it is the difference between the actual number of connections within a detected community and the expected number of connections under random conditions. A larger difference indicates that the result is less randomized and the community detection effect is more effective. Modularity can be formally expressed as:
[0100]
[0101] Where A ij The weight of the edge between node i and node j is represented by ki; the sum of the weights of the edges connected to node i is represented by k. j c represents the sum of edge weights connected to node j; i Indicates the community to which node i belongs; c j Indicates the community to which node j belongs; δ(c i ,c j ) indicates whether node i and node j belong to the same community. If they do, the value is 1, otherwise it is 0; m is the sum of the weights of all edges in the network.
[0102] The modularity gain ΔQ represents the change in the network's modularity when node i is moved to the community of node j, and can be formally expressed as:
[0103]
[0104] Where ∑ in ∑ represents the sum of edge weights within community C; tot k represents the sum of the edge weights connected to all nodes within community C; i k represents the sum of the weights of all edges connected to node i; i,in represents the sum of the edge weights connecting node i to nodes within community C; m is the sum of the edge weights in the network.
[0105] Local shifts based on modularity gain, such as Figure 5 As shown, for simplicity, the edge weights between nodes on the left side of the diagram are all 1. After the local move, closely connected nodes are moved to the same module. Nodes of the same color in the diagram indicate that they are in the same module after the move, while the connections between modules are relatively sparse.
[0106] The local move algorithm based on modularity gain is shown below. The input of this algorithm is the set of function nodes V, the set of function-dependent edges E, and the communities in which the nodes are located at this time. The output is the communities in which each node is located after the local move based on modularity gain.
[0107]
[0108] In this process, for each function node, the module containing the node is first initialized as the optimal module, and the module degree gain ΔQ is initialized to 0 (lines 5-6). The ΔQ required to move the node to the modules containing all its neighbors is calculated and recorded. The module with the largest ΔQ is selected (lines 7-12). If the largest ΔQ is greater than 0, the node is moved to the relevant module; otherwise, it remains in the original module (lines 13-15). This process is iteratively executed until no module degree gain greater than 0 exists after locally moving any node (lines 16-17).
[0109] 2.2.3 Module Combination
[0110] Module assembly process as follows Figure 6 As shown, the modules generated after local shifting based on module degree gain are merged into a new node. The dependencies between functions within a module are merged into self-loops within the new node, and the dependencies between new nodes are the dependencies between modules corresponding to the new node. The numbers on the edges in the diagram represent the edge weights between the new nodes after module combination.
[0111] The specific algorithm for module combination is shown below.
[0112]
[0113] This stage constructs a new network in which the nodes are modules from the previous stage (local movement based on module degree gain) (line 2), and the edges between nodes are the sum of the edge weights of the corresponding inter-module nodes (lines 3-7). Then, each new node is initialized in a new module (line 8).
[0114] Example 3: This example is mainly used to analyze the modular effect of the method of the present invention, and specifically includes the following contents.
[0115] 3.1 Experimental Data
[0116] To evaluate the effectiveness of the modular approach for binary programs proposed in this invention, this experimental example selected five commonly used program source codes of different sizes and compiled them into binary programs, collecting two adjacent versions for each program. During the compilation process, the symbol table of the binary program was preserved to obtain its truth information in subsequent analysis. A brief description of the binary program is shown in Table 1.
[0117] Table 1. Dataset information used for modular evaluation
[0118]
[0119]
[0120] 3.2 Comparison Methods
[0121] To evaluate the effectiveness of modularization, the proposed method BinMod was evaluated and compared with the source code modularization method FCA. Compared with state-of-the-art hierarchical and search-based algorithms, FCA achieves higher quality modularization and has a shorter runtime. This paper also compares BinMod with the state-of-the-art binary modularization method BCD.
[0122] 3.3 Evaluation Criteria
[0123] The experiment selected three evaluation criteria: algorithm stability, time efficiency, and algorithm performance, to evaluate the modularization method. Algorithm stability was used to evaluate the results of modularization between two similar versions of the program; time efficiency was used to evaluate the time consumed by the algorithm in processing modularization; and algorithm performance was used to compare the closeness between the algorithm's output and the true result.
[0124] The stability of the algorithm is used to evaluate the module partitioning results between two similar versions of the program. The modules of two similar versions of the binary program will not change significantly; therefore, a good modularization algorithm should produce similar results for adjacent versions of the binary program. The experiment uses MoJoFM to measure the stability of the algorithm. MoJoFM is defined as:
[0125]
[0126] Where mno(A,B) represents the minimum number of move or join operations required to convert the modular result A into B; the higher the MoJoFM score, the closer A is to B.
[0127] This experiment uses the V-measure to measure the algorithm's performance. This metric compares how close the algorithm's output is to the true result. The V-measure is the harmonic mean of the homogeneity and completeness measures.
[0128] Suppose a dataset contains N data points, C = {c i |i=1,...,n} represents a set of truth classes for data points; K={k i |i=1,...,m} represents a clustering result of data points; A={a ij} is a related table, where a ij c represents the category i The included data points are divided into cluster k i The number of items in the list.
[0129] A cluster is considered homogeneous if it contains data points belonging to only a single category. Homogeneity is defined as follows:
[0130]
[0131] In the formula: H(C|K) is the conditional entropy of the category partitioning given the clustering conditions.
[0132]
[0133] H(C) is the category partitioning entropy.
[0134]
[0135] If all data points of a category are distributed in a single cluster, then the cluster satisfies completeness. Similarly, homogeneity is also satisfied. Completeness is defined as:
[0136]
[0137] in:
[0138]
[0139]
[0140] The V-measure is the harmonic mean of the homogeneity and completeness measures. It is defined as follows:
[0141]
[0142] Where δ represents the weights for homogeneity and integrity. In this experimental example, δ is set to 1, indicating that the weights for homogeneity and integrity are the same. A higher V-measure value indicates a better partitioning effect.
[0143] 3.4 Parameter Selection
[0144] This section introduces the experimental analysis of parameter selection, including edge weight parameters during the construction of the functional dependency graph and the selection of similarity thresholds when moving between similar neighbors. Experiments were conducted by selecting different values for these parameters; the experimental process for parameter selection is referenced from DeepBinDiff.
[0145] 3.4.1 Edge weight parameters
[0146] In the construction of the function dependency graph, hyperparameters α, β, and γ represent the contributions of function call dependencies, data reference dependencies, and code local dependencies, respectively. To experimentally obtain their values, α ∈ [0,1], β ∈ [0,1], and γ = 1 - α - β (with a fixed similarity threshold of 0.7), where α and β vary from 0 to 1 in increments of 0.1. The V-measure values for each parameter are as follows: Figure 7 As shown, since there are 10 binary programs, the graph displays the average V-measure value for all programs under different parameters. Furthermore, based on the changing trends of the V-measure values for different parameters, the combined results of 5 sets of α values (0.3, 0.4, 0.5, 0.6, 0.7) and 4 sets of β values (0.1, 0.2, 0.3, 0.4) are presented. The graph shows that the V-measure score is highest when α = 0.5 (call relationship dependency weight) and β = 0.2 (data reference dependency weight).
[0147] In this experimental example, these parameters differ from those obtained from the BCD method experiment (call dependency weight: 0.362, data reference dependency weight: 0.4, code locality dependency weight: 0.237). Further research revealed that BCD only clusters methods within a single C++ class into a module. Since C++ is highly coupled with data operations due to data encapsulation, the weight of data reference dependencies is relatively high. However, in real-world applications, most large-scale programs are written in C. The experiment involved clustering functions performing a specific sub-function across multiple files into a single module. Different functions access the same data using global variables or parameters, with the latter being more prevalent. This results in a lower data dependency weight compared to C++.
[0148] 3.4.2 Similarity Threshold
[0149] The similarity threshold determines whether a node can be moved to the module containing its neighbors, and this value affects the module's performance. If the value is set too low, nodes with low similarity will be merged together; if it is set too high, functions that belong to the same module will be separated, resulting in them not being merged into one module. Figure 8The figure shows the V-measure values when different similarity thresholds are selected. The experiment used similarity thresholds of 0.6, 0.7, 0.8, 0.9, and 1 (with edge weight parameters fixed at α = 0.5, β = 0.2, and γ = 0.3). As can be seen from the figure, for the bison129 program, the highest V-measure (0.5404) is achieved with a similarity threshold of 0.65, which is 0.0054 higher than the V-measure value of 0.5350 with a similarity threshold of 0.7. For the busybox1320, busybox1321, and gdb92 programs, the highest V-measure is achieved with a similarity threshold of 0.75, which is 0.0056, 0.0148, and 0.0061 higher than the similarity threshold of 0.7, respectively. In the remaining cases, the highest V-measure value is achieved with a similarity threshold of 0.7. Based on the above analysis, a similarity threshold of 0.7 is chosen as the default similarity threshold for this analysis.
[0150] 3.5 Experimental Results and Analysis
[0151] This experiment demonstrates and analyzes the modularization effect of BinMod on binary programs. The modularization method BinMod is compared with the current best modularization methods FCA and BCD. Experimental results show that BinMod outperforms the latter two methods.
[0152] 3.5.1 Effects of the Method of the Invention
[0153] To evaluate the performance of BinMod (α = 0.5, β = 0.2, γ = 0.3, similarity threshold 0.7), it was compared with the alignment methods FCA and BCD, and also with the original community detection algorithm Louvain. The V-measure metric was used to measure the effectiveness of the modularization results. The comparison results of several methods are shown in Table 2, where "Improvement (%)" indicates the percentage improvement in the V-measure value of the BinMod partitioning results compared to other methods. Finally, the average of the 10 programs was calculated.
[0154] Table 2 Comparison of V-measure values between BinMod and other methods
[0155]
[0156]
[0157] The results show that BinMod achieved a higher V-measure value compared to other methods (an average improvement of 17.60%, 3.42%, and 5.24% compared to BCD, FCA, and Louvain methods, respectively).
[0158] 3.5.2 Algorithm Time Efficiency
[0159] This experiment uses the algorithm's runtime to evaluate its time efficiency. The results are shown in Table 3, which compares the runtime of the three methods. T(BinMod) / T(FCA) represents the ratio of the time taken by the BinMod method to that taken by the FCA method.
[0160] Table 3 Comparison of running time (seconds) of BinMod with other methods (from top to bottom, number of functions included in the program increases)
[0161]
[0162] The results show that BinMod's runtime is significantly shorter than both FCA and BCD. The BinMod method is significantly superior to the FCA algorithm (averaging 7.95% of the time spent by FCA), and this difference becomes more pronounced as the number of functions increases. As the number of functions increases, FCA's performance slows down, and it also encounters memory issues because it needs to first construct an n*n function dependency matrix and then perform operations on this matrix (where n represents the number of functions).
[0163] T(BinMod) / T(BCD) represents the ratio of the time spent by the BinMod method to that spent by the BCD method (on average, BCD takes 21.51% of the time). The time complexity of the BCD method is O((m+n)*n), where m represents the number of edges and n represents the number of functions. Experiments evaluated the time complexity of BinMod: in the first stage of moving similar neighbors, the time complexity is O(m), where m represents the number of node connections (edges). For the second and third stages, the Louvain algorithm is used to maximize modularity, and their average time complexity is nlog(n), where n represents the number of nodes. Therefore, the overall time complexity of BinMod is O(m+nlog(n)), which is efficient for handling complex large-scale binary programs.
[0164] 3.5.3 Algorithm Stability
[0165] Stability reflects the sensitivity of a modular algorithm to changes in input data. A modular algorithm with good stability should produce similar modules when the program undergoes small changes. Therefore, two adjacent versions of the binary program are used to compare the stability of the algorithm. n ) = MoJoFM(M n M n-1 ), where M n and M n-1 This represents the module results produced by two consecutive versions of the program. The results are shown in Table 4.
[0166] Table 4. Stability comparison of BinMod with other methods
[0167]
[0168] As shown in Table 4, except for the bash program, BinMod's stability is higher than FCA and BCD, and the improvement is significant. Therefore, overall, BinMod outperforms FCA and BCD in terms of stability (with average improvements of 8.28% and 30.87%, respectively).
Claims
1. A modular approach for binary programs, characterized in that: The following steps are involved: Step 1: Disassemble the binary function and extract its function dependencies, constructing a function dependency graph. Nodes in the graph represent functions, and edges represent dependencies between functions. The function dependencies include function call dependencies, data reference dependencies, and local code dependencies. Function call dependencies include direct call dependencies and co-reference dependencies. Step 2: Divide the function dependency graph into modules containing various function sets, including the following steps: S1. Similar Neighbor Movement: Input the node set V, the function edge dependency set E, and the similarity threshold w. Treat each node as an independent module, merge nodes based on similar neighbor movement, and calculate the similarity value SV between each node and all its neighbors using Jaccard distance during the similar neighbor movement process. ij This yields the set of similarity values (SVs) between the node and all its neighboring nodes. In the formula: N(i) and N(j) represent the neighbors of node i and node j, respectively; Select the largest SV from SVs; if the largest SV value is higher than the similarity threshold w, move the node to the module of the neighbor node with the largest SV value; otherwise, the node remains in its original module; output the communities of each node. S2. Local movement based on modularity gain: input function node set V, function dependency edge set E, and the community where the node is located at this time; For each function node, firstly, the module where the node is located is initialized as the best module and the module degree gain is initialized to 0. Then, the module degree gain of moving the node to the modules where all its neighboring nodes are located is calculated and recorded, and the module with the largest module degree gain and the associated module is selected. If the maximum modularity gain is greater than 0, move the node to the relevant module; otherwise, leave it in the original module. Iterate until no node has a modularity gain greater than 0 after the local move. Then output the communities of each node generated after the local move based on the modularity gain. S3, Module Combination: The modules generated after local movement based on modularity gain are merged into a new node. The dependencies between functions within a module are merged into self-loops of the new node, thus constructing a new network. The nodes in the new network are modules based on local movement based on modularity gain, and the dependencies between the new nodes are the dependencies between the corresponding modules of the new nodes.
2. The modular method for binary programs according to claim 1, characterized in that: For data reference dependencies, strings are used as data. To obtain the data referenced by each function, each instruction of the function is traversed, and it is determined whether each instruction cross-references the offset address of the string stored in the .rodata segment. All offset addresses that cross-reference the string stored in the .rodata segment are obtained and mapped to the function. For each function, the mapping relationship is expressed as: Φ:f→D,D= <D1,...,D m >, where D i Let represent the i-th string accessed by function f. After traversing all functions, if function A and function B access the same data, then an edge is established from function A to function B. A large number of shared data references between functions A and B means they are more likely to belong to the same module. The edge weight dependent on data references is equivalent to the number of times the data is referenced. In the formula: It is the data reference dependency weight of function i and function j; y d It refers to the number of times the same data is referenced; E d It is a set of data reference dependency edges.
3. The modular method for binary programs according to claim 2, characterized in that: To address code locality dependencies, first sort all functions by address, then construct an edge with weight 1 between any two adjacent functions; sorting the functions by address yields a set f1, f2, ..., f n The weights of the constructed code locality dependency edges are: In the formula: It is the code local dependency weight of function i and function j.
4. The modular method for binary programs according to claim 3, characterized in that: After extracting all functional dependencies, when constructing the functional dependency graph, considering the possibility of edges between different modules, a weighted functional dependency graph G = (V, E, W) is built, with the weights being a combination of the three types of dependencies. In the formula: W ij It is the sum of the dependency weights of functions i and j; This represents the function call dependency weight; the parameters α, β, and γ represent the contributions of function call dependency, data reference dependency, and code local dependency, respectively; α + β + γ = 1.
Citation Information
Patent Citations
Elevator mechanical structure modeling and module dividing method based on complex network
CN113515823A
Mail mining method based on coarsening and local overlapping modularity
WO2020253150A1