An indirect call target recovery method for unsigned binary programs
By constructing a function-level stack-aware type flow graph and K-window offset inference, combined with program-level iterative on-demand collaborative analysis, the problems of insufficient coverage and high false alarms in indirect call target recovery in unsigned binary programs are solved, achieving efficient and accurate target recovery.
Patent Information
- Authority / Receiving Office
- CN · China
- Patent Type
- Applications(China)
- Current Assignee / Owner
- NANJING UNIV
- Filing Date
- 2026-05-08
- Publication Date
- 2026-07-31
AI Technical Summary
Existing technologies struggle to simultaneously recover function address propagation relationships and object offset constraints in unsigned binary programs, resulting in insufficient coverage of indirect call target recovery results, numerous false alarms, and high program-level analysis overhead.
We employ a method that combines function-level stack-aware type flow graphs, K-window offset inference, and program-level iterative on-demand collaborative analysis. By integrating function address propagation relationships and object offset compatibility, we recover indirect call targets through static information extraction, function-level stack-aware type flow graph construction, K-window offset inference, and program-level type flow graph collaborative analysis.
Without relying on full high-level type recovery, the range of candidate targets is narrowed, false positives are reduced, the target matching distortion caused by global object splitting is alleviated, and the integrity of indirect call target recovery is improved while keeping the analysis overhead under control.
Smart Images

Figure CN122489157A_ABST
Abstract
Description
Technical Field
[0001] This invention relates to the field of binary program analysis, and more particularly to a method for recovering indirect call targets for unsigned binary programs. Background Technology
[0002] With a large number of commercial software, firmware, and industrial control programs being released in unsigned binary form, the demand for security analysis targeting source-free objects continues to grow. Typical tasks such as taint analysis, symbolic execution, vulnerability detection, and reachability analysis often rely on high-quality call graphs, and the quality of the call graph largely depends on whether the indirect call targets can be accurately recovered.
[0003] In scenarios involving function pointers, callback mechanisms, function tables, and virtual function dispatch, the target of an indirect call is typically obtained indirectly through registers or memory; the target address does not appear explicitly in the call instruction. If the recovery result is too broad, it will introduce numerous spurious paths and increase analysis noise; if the recovery result is incomplete, it will truncate the cross-function propagation link and cause the omission of the true path.
[0004] Existing methods for indirect call target recovery mainly include static methods based on type or signature constraints, static methods based on value propagation or pointer analysis, dynamic auxiliary methods that incorporate runtime information, and methods based on learning models. While these methods improve target recovery capabilities to some extent, they are still limited in unsigned binary scenarios by factors such as weakened type information, missing object boundaries, insufficient dynamic coverage, and high program-level analysis overhead.
[0005] In unsigned binary scenarios, one type of technical difficulty in existing technologies lies in the decomposition of local objects. Scalar substitution, register allocation, and stack variable splitting during compiler optimization can cause the write and read positions of fields that originally belonged to the same local object to appear as multiple independent local variables in the decompiled results, making it difficult for the caller to recover the internal offset relationships of the object.
[0006] In unsigned binary scenarios, another technical challenge in existing technologies lies in the splitting of statically initialized global objects. Logically contiguous function tables, callback tables, or scheduling tables may be split into multiple globally accessible but symbolically independent entries after compilation and linking. If the repetitive layout relationships between these global entries cannot be restored, it becomes difficult to determine which field in the logical object the call point accesses.
[0007] Furthermore, performing a complete full-program propagation analysis directly on a large number of symbols typically incurs high time and space overhead. Therefore, a technical solution is needed that can simultaneously recover function address propagation relationships and object offset constraints, and complete the collaborative analysis within the program scope in a cost-effective manner. Summary of the Invention
[0008] Purpose of the invention: The technical problem to be solved by the present invention is to provide a method for recovering the indirect call target of unsigned binary programs, which addresses the shortcomings of the prior art.
[0009] To address the aforementioned technical problems, this invention discloses a method for recovering the indirect call target of an unsigned binary program, comprising the following steps:
[0010] Step 1: Perform static information extraction on the unsigned binary program to be analyzed to form the structured intermediate information required for subsequent analysis. The structured intermediate information includes at least the decompiled statements, the relative position information of local stack variables, the layout information of statically initialized global objects, the information of the functions whose addresses are taken, the information of indirect call points, and the information of candidate global objects.
[0011] Step 2: Construct a function-level stack-aware type flow graph based on the decompiled statements to uniformly represent the relationships of field access, value propagation, and local stack layout related to function address propagation.
[0012] Step 3: Perform K-window offset inference on the statically initialized global object, identify duplicate layout units, determine the expected offset set of candidate global object items and the mapping relationship between the offset positions and the candidate objective function set.
[0013] Step 4: Construct a program-level type flow graph based on the function-level stack-aware type flow graph and existing call relationships for each function, identify the propagation starting point, and assign an initial set of allowed offsets to each propagation starting point.
[0014] Step 5: Perform iterative on-demand collaborative analysis on the program-level type flow graph, match the allowed offset set obtained from the propagation at the call point with the expected offset set at the target point, and restore the candidate objective function set for each indirect call point.
[0015] Step 6: Incrementally expand the program-level type flow graph based on the newly restored call edges in this round, and repeat Step 5 until no more new call edges are restored, and output the indirect call target restoration result.
[0016] The static information extraction is completed during the online extraction phase;
[0017] The construction of the function-level stack-aware type flow graph, K-window offset inference, program-level type flow graph collaborative analysis, and result output are all completed in the offline analysis phase.
[0018] Furthermore, the graph nodes in the function-level stack-aware type flow graph are field-aware symbols, which are composed of base address symbols and relative offsets; the graph edges include at least data flow edges for representing value propagation caused by assignment, loading and storage, field edges for representing the intra-object offset relationship between field nodes and corresponding base objects, and stack offset edges for representing the relative positional relationship between different stack slot base nodes.
[0019] Furthermore, the K-window offset inference includes K-element window inference and K-symbol window inference. If elements at corresponding positions in different K-windows have the same coarse-grained type, or if one element is a function pointer or an address that can be interpreted as pointing to a program segment while the other element has a zero value, then the different K-window layouts are determined to be compatible.
[0020] Furthermore, the static information extraction is completed in the online extraction stage, while the function-level stack-aware type flow graph construction, K-window offset inference, program-level type flow graph collaborative analysis, and result output are completed in the offline analysis stage.
[0021] Beneficial effects:
[0022] Because it uses an analysis criterion that combines function address propagation relationship with object offset compatibility, it can constrain indirect call targets in unsigned binary without relying on full high-level type recovery, thus narrowing the range of candidate targets and reducing false alarms.
[0023] Because a function-level stack-aware type flow graph is constructed, incorporating field access, data propagation, and stack relative positions into the same function-level graph structure, it is possible to re-establish the correspondence between the call point value location and the function address write location after local object decomposition.
[0024] By using K-element window inference and K-symbol window inference to restore the repetitive layout relationships and expected offsets in the statically initialized global object, the target matching distortion problem caused by global object splitting and reorganization can be alleviated.
[0025] By employing program-level iterative on-demand collaborative analysis and limited rollback compensation, it is possible to improve the integrity of indirect call target recovery while maintaining overall controllable analysis overhead, and to provide a foundation for call graph recovery, vulnerability detection, and cross-function program analysis. Attached Figure Description
[0026] Figure 1 This is an overall flowchart of an indirect call target recovery method for unsigned binary programs provided in an embodiment of the present invention.
[0027] Figure 2 This is a schematic diagram of a local cross-function stack-aware type flow graph in the local object decomposition scenario of this invention.
[0028] Figure 3 This is a schematic diagram illustrating the K-window offset inference in a global static object splitting scenario according to an embodiment of the present invention.
[0029] Figure 4 This is a flowchart of the program-level iterative on-demand collaborative analysis in an embodiment of the present invention. Detailed Implementation
[0030] This invention addresses the problem that existing technologies struggle to simultaneously recover function address propagation relationships and object offset constraints in unsigned binary programs, leading to insufficient coverage of indirect call target recovery results, numerous false alarms, and high program-level analysis overhead. It proposes an indirect call target recovery method for unsigned binary programs.
[0031] like Figure 1 As shown, the indirect call target recovery method provided in this embodiment of the invention takes an unsigned binary program as input and first performs static information extraction. The static information extraction result is used to construct a function-level stack-aware type flow graph and to perform K-window offset inference. Subsequently, the function-level stack-aware type flow graph and the K-window offset inference result are used together to construct a program-level type flow graph, and iterative on-demand collaborative analysis is performed on the program-level type flow graph to finally output the indirect call target recovery result. The unsigned binary program can be an executable file, a shared library, a user-space program module in a firmware image, or other binary objects that can recover control flow and data access relationships in a decompilation environment. The following uses the local object decomposition scenario and the global static object splitting scenario in the executable file as two parallel examples to illustrate the specific processing process of this method under different object layout scenarios.
[0032] The following provides a detailed description of each step of the method of the present invention, and combines steps 2 and 3 with the program-level iterative analysis section. Figure 2 The example shown is a partial object decomposition. Figure 3 The example shown is a global static object splitting example and Figure 4 The program-level flow shown is explained below.
[0033] Step 1 involves extracting static information from the unsigned binary program to be analyzed. Step 1 includes the following sub-steps:
[0034] Step 1-1 extracts function-level decompiled statements, assignment relationships, memory load and store expressions, indirect call points, address fetch operations, and local variable stack address offsets. Among these, assignment relationships and memory load and store expressions are used to identify data flow edges and field edges; indirect call points are used to locate the caller's access position to be matched; and address fetch operations and local variable stack address offsets are used to identify the propagation starting point and stack offset edges.
[0035] Steps 1-2 extract the address range, element span, element type information, and nameable global symbol information of the statically initialized global object. This information is used for subsequent K-window offset inference and identification of candidate global object items. The global symbol refers to a statically stored named data object or its starting address identifier that can be located in a decompiled or binary analysis environment. The candidate global object item refers to a global data item located within the statically initialized global object or its fragmented segments that may store function addresses or participate in function pointer access matching.
[0036] Steps 1-3: Extract the information of the function whose address is taken and the information of the candidate global object items.
[0037] The address-of function refers to the target function whose address is directly referenced during assignment, field writing, parameter passing, or static initialization. The address-of function information includes at least the target function address and the corresponding reference position. The candidate global object item information includes at least the relevant item address, the global object to which it belongs, the element span, the coarse-grained type, and the position within the object.
[0038] Furthermore, candidate global object items can be obtained by performing layout scanning and coarse-grained type filtering on statically initialized global objects; each candidate global object item records its own global object, its offset within the object, its element type, and its set of candidate objective functions.
[0039] The static information extraction can be performed in a decompilation environment or by other binary enhancement tools that can provide an equivalent intermediate representation. The extraction result can be serialized into a reusable structured intermediate representation for subsequent analysis.
[0040] Step 2 involves constructing a function-level stack-aware type flow graph based on the decompiled statements, and unifying the field access, value propagation, and local stack layout relationships related to function address propagation into the function-level stack-aware type flow graph. Step 2 includes the following sub-steps:
[0041] Step 2-1: Traverse the decompiled statements, extract field-aware symbols, and fill in the missing base nodes.
[0042] The field-aware symbol consists of a base address symbol and a relative offset, where the relative offset can be a base node marker ε representing the base object itself, a non-negative offset, or an indeterminate offset marker. Figure 2 Taking Figure (b) as an example, a1@ε and v19@ε represent base nodes, and a1@0x38, a1@0x40 and v24@8 represent field nodes with offsets; the uncertain offset marker is used to retain access situations that can only be determined at runtime and does not directly participate in subsequent precise offset compatibility determination.
[0043] Specifically, for statically known offset access, a field node of "base address symbol @ offset" is constructed; for cases where the field appears only in the form of a field but the base node is missing, the corresponding base node is added. The extracted field-aware symbols are used to determine graph nodes, and the field edges are used to associate field nodes with their base nodes, thereby uniformly mapping object field accesses in different decompiled statements to the same graph structure.
[0044] Step 2-2: Establish data flow edges based on assignment statements, field read statements, and field write statements.
[0045] Steps 2-3: Establish field edges based on the relationship between non-base field nodes and their corresponding base nodes.
[0046] Steps 2-4 involve establishing stack offset edges with offset markers based on the stack address differences of local variables. After establishing these stack offset edges, the relative layout of the same logical local object across multiple stack slot variables can be restored.
[0047] The construction method in step 2 above can be combined with Figure 2 The local object decomposition scene shown will be further illustrated. Figure 2 Taking the decompiled code shown in Figure (a) as an example, the initialization side function sub_4840 writes the function addresses sub_4AD0 and sub_4AE0 into a1[7] and a1[8] respectively; the calling side function sub_6C60 passes &v19 as an actual parameter to sub_4840, and reads the function pointer through two indirect calls in the form of *(&v24+1). Step 2 constructs the corresponding function-level stack-aware type flow graphs based on the decompiled statements of the initialization side function and the calling side function, and connects the calling side actual parameter and the initialization side formal parameter through inter-procedural edges to form Figure 2 The example of a local cross-function stack-aware type flow graph is shown in Figure (b).
[0048] In addition to the process edges mentioned above, Figure 2 The edges in the function graph in Figure (b) mainly include data flow edges, field edges, and stack offset edges. Data flow edges represent value propagation relationships caused by assignment or field read / write operations; field edges represent the intra-object offset relationship between a field node and its corresponding base node; and stack offset edges represent the relative positional relationship between base nodes in different stack slots. In this example, v19 is located at [rsp+8], and v24 is located at [rsp+0x40], with a relative offset of 0x38. Combining this with the 0x8 field offset introduced by *(&v24+1), we can obtain 0x38+0x8=0x40, thus determining that the call point actually accesses the function pointer field at offset 0x40.
[0049] Generally, for the set of stack relative offsets propagated to the call point, each stack relative offset is superimposed with the field access offset carried by the call expression itself to obtain the set of offsets within the synthesized object on the call point side; the set of offsets within the synthesized object on the call point side is used to represent the offset position within the object actually accessed by the call point.
[0050] Step 3: Perform K-window offset inference on the statically initialized global object to identify repeating layout units and determine the expected offset set and the mapping relationship between the offset positions and the candidate objective function set for candidate global object items. The K-window offset inference includes K-element window inference and K-symbol window inference. K-element window inference is used to identify repeating element sequences within the statically initialized layout, and K-symbol window inference is used to identify split continuous layouts between adjacent global symbols.
[0051] like Figure 3 As shown, Figure 3 Figure (a) shows the structure definitions, static initializations, and access statements in the source code. Figure 3 Figure (b) shows the optimized static object splitting result. Figure 3 Figure (c) shows the decompiled code corresponding to the call point. Figure 3 Figure d in the figure illustrates the candidate target selection process based on the expected window offset.
[0052] In K-element window inference, the statically initialized layout refers to the sequence of elements recovered from the statically initialized global object in address order, with the target architecture pointer width as the unit. For one or more pre-defined K values, K consecutive elements are sequentially extracted from the element sequence to form a K-element window, where K represents the number of consecutive elements contained in the window. By comparing the layout compatibility of different K-element windows, element sequences belonging to the same repeating layout are identified, and the expected offset of candidate global object items relative to candidate base addresses is determined accordingly.
[0053] by Figure 3 Taking the source code scenario shown in Figure (a) as an example, the logical directive entry consists of three slots: handler, name, and handler2, arranged according to pointer width. Figure 3 In the binary-side static initialization layout shown in Figure (b), the structure is represented by consecutive slots such as sub_70CB0, “define”, and sub_70D00, as well as subsequent slots with the same structure; therefore, when K is 3, the three consecutive slots truncated from the entry header constitute a 3-element window.
[0054] Furthermore, the K-symbol window inference is used to identify split, contiguous layouts between adjacent global symbols, and the K-symbol window inference may include the following sub-steps:
[0055] Step 3-1: Extract the first K-element window for each adjacent global symbol arranged in ascending order of address. For example, in... Figure 3 In Figure (b), the first 3-element window is captured from the starting positions of off_33A990 and off_33AA68, respectively.
[0056] Step 3-2: Determine whether the layouts of the first K-element windows are compatible in pairs. For example, if the corresponding slots of the two windows both present a coarse-grained type sequence of "function address, string or non-code address, function address", then the layouts are determined to be compatible.
[0057] Step 3-3: When the first K-element window is compatible in both layouts, the corresponding adjacent global symbols are regarded as continuous segments of the same logical object, and the expected offset of the candidate global object items scattered in different global symbols is recalculated under the unified candidate base address set.
[0058] by Figure 3 Taking Figure (b) as an example, logically consecutive directive entries after compilation optimization can be split into independent global symbols such as off_33A990 and off_33AA68. A 2-symbol window covers off_33A990 and off_33AA68, and determines whether they belong to the same static initialization layout based on the coarse-grained type sequence compatibility of their first 3-element windows. In this example, since each directive entry contains three slots arranged by pointer width: handler, name, and handler2, a candidate base address step size of 0x18 can be obtained in a 64-bit architecture; correspondingly, the expected offset of the handler item at the beginning of the entry is 0, and the expected offset of the handler2 item in the third slot is 16.
[0059] When elements at corresponding positions in different K windows have the same coarse-grained type, or when one element is a function pointer or an address entry that can be interpreted as pointing to a program segment while the other element has a zero value, the different K window layouts are considered compatible.
[0060] After completing K-element window inference and K-symbol window inference, the expected offset set is determined and maintained for each candidate global object item, and a mapping relationship is established between the offset positions and the candidate objective function set. Figure 3 Taking Figure d as an example, Figure 3 In Figure (c), v4 is obtained by adding an entry offset with a step size of 3 slots to off_33A990. Subsequently, v6 is taken from v4 and an indirect call is initiated through (*v6)(a1). Since no additional field offset is added at this call point, its corresponding... Figure 3In Figure (a), the entry starting function pointer field shown in the handler has a call point offset of 0. Therefore, when filtering by expected offset in the candidate symbol set within the window, a group of candidate targets with an expected offset of 0 is retained, while a group of candidate targets with an expected offset of 16 is excluded. The expected offset set and the mapping relationship together constitute the target-side offset information used in step 5.
[0061] The process of determining and maintaining the expected offset set specifically includes:
[0062] For repeated layouts identified within a single global symbol, the starting positions of each window within the address range of the global symbol, which increase by K elements, are used as candidate base addresses.
[0063] For repeated layouts obtained by merging adjacent global symbols, the starting position of the adjacent global symbol with the lowest address is used as a unified starting point, and a candidate base address sequence is generated with the same span.
[0064] For a candidate global object item located within the coverage area of the repeated layout, the candidate base address that is no more than the address of the candidate global object item and has the smallest difference from its address is selected from the candidate base address set as the corresponding base address. The difference between the address of the candidate global object item and the corresponding base address is then incorporated into the expected offset set of the candidate global object item. The candidate base address set can be a set of candidate base addresses obtained from repeated layouts within a single global symbol, or a unified set of candidate base addresses obtained by merging adjacent global symbols.
[0065] If the same candidate global object item is constrained by multiple duplicate layout sources, the difference corresponding to each source is merged into its expected offset set.
[0066] Step 4: Construct a program-level type flow graph based on the function-level stack-aware type flow graph corresponding to each function and the existing call relationships. The program-level type flow graph consists of the function-level stack-aware type flow graph corresponding to each function and inter-procedural propagation edges. Step 4 includes the following sub-steps:
[0067] Step 4-1: Based on the function-level stack-aware type flow graph corresponding to each function, incorporate the data flow edges, field edges, and stack offset edges within the function into the program-level type flow graph.
[0068] Step 4-2: Establish inter-procedural propagation edges based on existing calling relationships. Preferably, the inter-procedural propagation edges include propagation edges from actual parameter nodes to formal parameter nodes, and propagation edges from the return value node of the called function to the variable receiving node of the calling point.
[0069] Step 4-3: Identify the propagation starting point and assign an initial set of allowed offsets to each propagation starting point.
[0070] To prevent the spread of irrelevant states, the propagation starting point must include at least the function whose address is being fetched, the global object related to the function's address, and the local address-fetching base node identified by the address-fetching operation.
[0071] Among them, the global objects related to function addresses are global objects that directly carry function addresses or contain function address items or function address layouts in the static initialization layout; the local address-fetching base nodes are the base nodes that participate in the address-fetching operation for the corresponding local variables.
[0072] Symbols that participate in scalar transformations that clearly violate pointer semantics, those that only participate in comparisons for equality or inequality with non-zero constants, those that only participate in unary operations other than logical NOT and address taking, or those whose bit width is smaller than the pointer width of the current architecture, will not be used as propagation starting points.
[0073] For the function whose address is being fetched and the global object associated with that function address, the initial set of allowed offsets can be a placeholder offset representing the base starting point; for the local fetch base node, the initial set of allowed offsets can be an initial offset determined by the relative position on the stack.
[0074] by Figure 2 The example of local object decomposition shown illustrates step 4, where each function can specifically correspond to sub_4840 on the initialization side and sub_6C60 on the calling side. Figure 2 The local cross-function stack-aware type flow graph shown in Figure (b) can be understood as being composed of field access, data flow edges, stack offset edges, and inter-process edges connecting the two in the relevant statements of sub_4840 and sub_6C60. Figure 4 The program-level flow shown corresponds to writing the address of the initialization side function and connecting it with the access of the indirect call point on the calling side, and updating it iteratively, based on the existing call relationship.
[0075] Step 5: Perform iterative on-demand collaborative analysis on the program-level type flow graph, matching the allowed offset set obtained from propagation at the call point with the expected offset set at the target point, and recovering the candidate objective function set for each indirect call point. Step 5 includes the following sub-steps:
[0076] Step 5-1: Propagate the allowed offsets along the data flow edges, field edges, stack offset edges, and inter-procedural propagation edges;
[0077] When the propagation state reaches the indirect call point, the allowed offset set on the call point side is obtained and matched with the expected offset set on the target side obtained in step 3;
[0078] Step 5-2: For local object scenarios, after the propagation state reaches the indirect call point, the stack relative offset obtained from the propagation is superimposed with the field access offset of the indirect call point itself to obtain the offset within the comprehensive object on the call point side.
[0079] When the offset within the synthesized object intersects with the target-side expected offset set corresponding to a certain address-tapped function, the address-tapped function is added to the candidate target function set of the indirect call point;
[0080] Step 5-3: For global object scenarios, determine the candidate objective function based on the intersection of the allowed offset set on the call point side corresponding to the indirect call point and the expected offset set of the corresponding candidate global object item.
[0081] For the target matching process, if the allowed offset set on the calling point side and the expected offset set on the target side intersect, then the calling point and the corresponding target object are determined to be compatible in terms of offset.
[0082] For global object scenarios, for each offset position in the intersection, query the set of candidate objective functions corresponding to that offset position, and merge the queried candidate objective functions into the set of candidate objective functions of the corresponding call point.
[0083] Step 5-4: When the process of propagating the allowed offset along the propagation edge fails to reach the call point where the target matching can be directly executed due to the incompleteness of the intermediate propagation chain, a restricted backoff compensation is performed.
[0084] The restricted backoff compensation only supplements the candidate objective function when the cumulative allowed offset on the calling point side and the expected offset on the target side meet the compatibility condition; if the compatibility condition is not met, backoff compensation is not triggered, thereby reducing false alarms while controlling the spread of false alarms.
[0085] Step 6: Summarize the newly recovered call edges from this round of analysis, and incrementally expand the inter-procedural propagation edges in the program-level type flow graph accordingly. The newly recovered call edges are generated by offset matching or restricted backoff compensation in Step 5. For example... Figure 4 As shown, if a new call edge is recovered in this round of matching, the program-level type flow graph is updated and step 5 is continued; if no new call edge is recovered, the result is considered to have reached a stable state, and the final indirect call target recovery result is output.
[0086] During the iterations of steps 5 and 6 above, the scope of analysis is not expanded indiscriminately. Offset propagation is limited to the identified propagation starting point and the relevant propagation edges in the program-level type flow graph; inter-process propagation edges are incrementally expanded only when a new call edge is restored in the current round; restricted backoff compensation is also triggered only when the cumulative allowed offset on the call point side and the expected offset on the target side meet the compatibility condition. Thus, on the one hand, irrelevant state propagation and false alarm propagation can be controlled; on the other hand, the inter-process propagation path reachable in subsequent rounds can be expanded through newly restored call edges, and candidate objective functions that satisfy offset constraints can be supplemented when the intermediate propagation chain is incomplete, thereby reducing missed recovery caused by object splitting, propagation chain breakage, or missing indirect call relationships.
[0087] by Figure 2 Taking the local object decomposition example shown, the "newly recovered call edge" refers to the call relationship between the newly identified indirect call point and the target function, based on the matching result of the call point side offset and the target side expected offset in step 5. For example, when step 5 establishes a correspondence between the indirect call in sub_6C60 and sub_4AE0, this correspondence can be used as a newly recovered call edge and used in step 6 for incremental expansion of the inter-process propagation edge.
[0088] The output includes at least the address of each indirect call point, the number of corresponding candidate target functions, and a list of candidate target function addresses. The output can also be used to construct a program call graph, or as input for binary program analysis tasks such as vulnerability detection, taint propagation, symbolic execution, and reachability analysis.
[0089] The output results can be combined separately. Figure 2 and Figure 3 The two examples shown are for understanding. Figure 2 In the local object decomposition scenario shown, the two indirect calls initiated by *(&v24+1) in sub_6C60, after the calculation of the stack relative position of v19 and v24 and the field displacement, correspond to the function pointer field at offset 0x40 of the original local object. Finally, it is restored to correspond to the function address sub_4AE0 written in sub_4840 with a1[8], instead of being confused with sub_4AD0 at offset 0x38.
[0090] exist Figure 3 In the global static object splitting scenario shown, the symbol window 2 identifies off_33A990 and off_33AA68 as adjacent fragments of the same static initialization layout, allowing them to share the entry span of 0x18 determined by 3 pointer width slots and the expected offsets corresponding to handler and handler2. Based on this, Figure 3 In Figure (c), the call point accessing the handler field of the directive entry via (*v6)(a1) has a call point offset of 0, therefore Figure 3 The candidate targets output by Figure d retain the set of handler functions with expected offset of 0, such as sub_70CB0, sub_70DE0, ..., sub_71300, and exclude the set of handler2 functions with expected offset of 16, such as sub_70D00, sub_70EB0, ..., sub_71390.
[0091] Therefore, in the scenario of local object decomposition, the present invention can restore the field correspondence between the split stack slots; in the scenario of global static object decomposition, the present invention can make the adjacent global symbols that are split participate in offset matching according to the same layout, avoid the mixing of the corresponding functions of handler and handler2, and improve the recovery, completeness and accuracy of indirect call targets.
[0092] At the system implementation level, the method can adopt a two-stage architecture combining an online extraction stage and an offline analysis stage. The online extraction stage extracts decompiled statements, local stack layout information, statically initialized global object layout information, and indirect call related information from the decompilation environment, and organizes this information into a structured intermediate representation. The offline analysis stage reads the structured intermediate representation and sequentially performs function-level stack-aware type flow graph construction, global layout preprocessing and index construction, program-level type flow graph co-analysis, and outer fixed-point iteration, outputting a set of candidate target functions for each indirect call point. By separating information extraction from target recovery analysis, multiple rounds of analysis and result reuse are facilitated without repeatedly performing online extraction.
[0093] This invention provides a concept and method for recovering the target of an indirect call in an unsigned binary program. Many methods and approaches exist for implementing this technical solution; the above description is merely a preferred embodiment of the invention. It should be noted that those skilled in the art can make various improvements and modifications without departing from the principles of this invention, and these improvements and modifications should also be considered within the scope of protection of this invention. All components not explicitly stated in this embodiment can be implemented using existing technologies.
Claims
1. A method for recovering the indirect call target of an unsigned binary program, characterized in that, Includes the following steps: Step 1: Perform static information extraction on the unsigned binary program to be analyzed to obtain decompiled statements, relative position information of local stack variables, layout information of statically initialized global objects, information of functions whose addresses are taken, information of indirect call points, and information of candidate global objects. Step 2: Construct a function-level stack-aware type flow graph based on the decompiled statements, and organize the field access, value propagation and local stack layout relationships related to function address propagation into the function-level stack-aware type flow graph; Step 3: Perform K-window offset inference for the statically initialized global object, identify duplicate layout units, and after completing the K-window offset inference, save the expected offset set for each candidate global object item and establish a mapping relationship between the offset position and the candidate objective function set. Step 4: Construct a program-level type flow graph based on the function-level stack-aware type flow graph and existing call relationships for each function, identify the propagation starting point, and allocate an initial set of allowed offsets for each propagation starting point; Step 5: Perform iterative on-demand collaborative analysis on the program-level type flow graph, match the allowed offset set obtained from the propagation at the call point with the expected offset set at the target, and restore the candidate objective function set for each indirect call point; Step 6: Incrementally expand the program-level type flow graph based on the newly restored call edges in this round, and repeat Step 5 until no more new call edges are restored, and output the indirect call target restoration result.
2. The method for recovering the indirect call target of an unsigned binary program according to claim 1, characterized in that, In step 2, the graph nodes in the function-level stack-aware type flow graph are field-aware symbols, which consist of a base address symbol and a relative offset. The graph edges include: data flow edges used to represent value propagation caused by assignment, loading, and storage; field edges used to represent the intra-object offset relationship between field nodes and their corresponding base objects; and stack offset edges used to represent the relative positional relationship between different stack slot base nodes.
3. The method for recovering the indirect call target of an unsigned binary program according to claim 2, characterized in that, Step 2 specifically includes: Traverse the decompiled statements, extract field-aware symbols and fill in missing base nodes; establish data flow edges based on assignment statements, field read statements and field write statements; establish field edges based on the relationship between non-base field nodes and their corresponding base nodes; establish stack offset edges with offset markers based on the stack address difference of local variables.
4. The indirect call target recovery method for unsigned binary programs according to claim 1, characterized in that, The K-window offset inference in step 3 includes K-element window inference. In K-element window inference: first, the static initialization layout is divided into an element sequence according to the pointer width of the target architecture; for one or more pre-set K values, K consecutive elements are extracted from a single global symbol to form a corresponding K-element window, where K represents the number of consecutive elements contained in the corresponding K-element window. By comparing the layout compatibility of the K-element windows, element sequences belonging to the same repeating layout are identified, and the expected offset of the candidate global object item relative to the candidate base address is determined accordingly.
5. The indirect call target recovery method for unsigned binary programs according to claim 4, characterized in that, The K-window offset inference in step 3 also includes K-symmetric window inference, which specifically includes the following steps: Step 3-1: Extract the first K-element window for each of the adjacent global symbols arranged in ascending order of address; Step 3-2: Determine whether the first K-element windows are compatible in their pairwise layouts; Step 3-3: When the first K-element window is compatible in both layouts, the corresponding adjacent global symbols are regarded as continuous segments of the same logical object, and the expected offset of the candidate global object items scattered in different global symbols is recalculated under the unified candidate base address set.
6. A method for recovering an indirect call target for an unsigned binary program according to claim 4 or 5, characterized in that, The layout compatibility determination is as follows: if elements in corresponding positions of different K windows have the same coarse-grained type, or if one element is a function pointer or can be interpreted as an address item pointing to a program segment while the other element has a zero value, then the different K window layouts are determined to be compatible.
7. The method for recovering the indirect call target of an unsigned binary program according to claim 1, characterized in that, The propagation starting point in step 4 includes the function whose address is being fetched, the global object related to the function address, and the local address fetching base node identified by the address fetching operation; wherein, the global object related to the function address is a global object that directly carries the function address or contains a function address item or function address layout in the static initialization layout, and the local address fetching base node is the base node corresponding to the local variable participating in the address fetching operation.
8. The method for recovering the indirect call target of an unsigned binary program according to claim 7, characterized in that, In step 5, the allowed offset is propagated along the data flow edge, field edge, stack offset edge, and inter-procedure propagation edge. If the propagation fails to reach the call point where the target matching can be directly executed, a candidate objective function is added only if the accumulated allowed offset on the call point side and the expected offset on the target side meet the compatibility condition. If the compatibility condition is not met, the restricted backoff compensation is not triggered.
9. A method for recovering an indirect call target for an unsigned binary program according to claim 8, characterized in that, For local object scenarios, after the propagation state reaches the indirect call point, the stack relative offset obtained from the propagation is superimposed with the field access offset of the indirect call point itself to obtain the offset within the comprehensive object on the call point side. When the offset within the synthesized object intersects with the target-side expected offset set corresponding to a certain address-fetched function, the address-fetched function is added to the candidate target function set of the indirect call point.
10. A method for recovering an indirect call target for an unsigned binary program according to claim 8, characterized in that, For global object scenarios, the allowed offset set of the call point corresponding to the indirect call point is intersected with the expected offset set of the corresponding candidate global object item, and for each offset position in the intersection, the candidate objective function is determined according to the mapping relationship between the offset position and the candidate objective function set.