An example plugin is included to copy all matched block names and instruction comments from one side of the differential analysis over to the other side, which is both useful as well as a nice example of how to interact with the diff results via the plugin framework. The contents of this plugins run() method can be seen below. If you are reading along it may be useful to consult the SDK documents as you go.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
processed_names = ::Set.new | |
processed_comments = ::Set.new | |
# cm will be the current model (A Relyze::ExecutableFileModel object), we | |
# hold the models read lock while we process the results... | |
cm.synchronize_read do | |
# First we pull out the existing differential analysis results that | |
# are being displayed in the GUI. We could however create the diff | |
# results programmatically by calling the models diff() method. | |
dr = @relyze.tab_current_diff | |
if( dr.nil? ) | |
print_error( "No diff results." ) | |
break | |
end | |
# Swap the DiffModelResult to the other side if we need to, e.g. the | |
# user right clicked on the B view and ran this plugin rather than | |
# the A view. This way we can easily copy from A to B or from B to A. | |
if( dr.model != cm ) | |
dr = dr.matched | |
end | |
print_message( "Copying comments from '#{dr.name}' to '#{dr.matched.name}'..." ) | |
# We iterate over every DiffFunctionResult on this side of the diff results. This | |
# will include all equal and modified functions matched between the two models as | |
# well as the functions found in this model but not the other. | |
dr.functions do | dr_func | | |
# We ignore removed or added functions as they are not matched to a corresponding | |
# item on the other side, so we cannot copy any names or comments over. | |
next if dr_func.is_removed? or dr_func.is_added? | |
# We now iterate over every DiffCodeBlockResult in this function. | |
dr_func.blocks do | dr_block | | |
# Again we ignore removed or added blocks as we cannot copy names | |
# or comments for unmatched items. | |
next if dr_block.is_removed? or dr_block.is_added? | |
# If this DiffCodeBlockResult's block has a custom name we can copy it over. | |
# A custom name is anything set by either the user of automatically by symbols. | |
if( copy_names and dr_block.block.custom_name? ) | |
# We check to see if we already copied this blocks name over. We do | |
# this as Relyze can associate a basic block with more that one function, | |
# and we may have already processed a function which contains this block | |
if( not processed_names.include?( dr_block.rva ) ) | |
# Before we copy the block name we must first grab the matched | |
# models write lock. | |
dr.matched.model.synchronize_write do | |
# We can now set the matched blocks name to this blocks name. | |
dr_block.matched.block.name = dr_block.name | |
# To avoid processing this block twice, add its RVA into a set. | |
processed_names << dr_block.rva | |
end | |
end | |
end | |
if( copy_comments ) | |
# Iterate over every DiffInstructionResult in this DiffCodeBlockResult | |
dr_block.instructions do | dr_inst | | |
# Ignore removed or added instructions | |
next if dr_inst.is_removed? or dr_inst.is_added? | |
# Ignore instructions where there is no comment to copy | |
next if not dr.model.comment?( dr_inst.rva ) | |
# Don't process the same comment twice (As we may see this block | |
# more than once via different functions containing the same block). | |
next if processed_comments.include?( dr_inst.rva ) | |
# Hold the matched models write lock before we copy the comment over. | |
dr.matched.model.synchronize_write do | |
# Grab the comment we want to copy over... | |
commentA = dr.model.get_comment( dr_inst.rva ) | |
# If the other side already has a comment at the matched location, | |
# we pull it out to see if its the same | |
if( dr.matched.model.comment?( dr_inst.matched.rva ) ) | |
commentB = dr.matched.model.get_comment( dr_inst.matched.rva ) | |
# If its the same comment we don't need to copy it | |
break if commentA == commentB | |
# If its not the same comment then we can preserve it during | |
# the copy. | |
commentA << "\r\n\r\nPrevious Comment:#{ commentB }" | |
end | |
# We can now add the comment to the matched location in the other model. | |
dr.matched.model.add_comment( dr_inst.matched.rva, commentA ) | |
# To avoid processing this comment twice, add its RVA into a set. | |
processed_comments << dr_inst.rva | |
end | |
end | |
end | |
end | |
end | |
end |
To try Relyze for yourself, download the latest trial. Existing users can use the builtin update feature to receive the latest version.