Today we are releasing Relyze 1.2.0 which focuses largely on the plugin framework and contains a number of important updates, including the addition of plugin support for binary diffing. The full change log can be found on the download page.

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.

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
Some additional updates in this release also include access to plugin shortcuts via a right click menu in the GUI and the ability to run plugins, via the command line, through a completely headless instance of Relyze.

To try Relyze for yourself, download the latest trial. Existing users can use the builtin update feature to receive the latest version.