Class: Crokus::TrojanInserter

Inherits:
Transformer show all
Defined in:
lib/crokus/trojan_inserter.rb

Constant Summary collapse

INT_TYPE =
Type.new(INT)
TROJAN =
%{
  void trojan(){
    u_=v_>0?v_:-v_;
    for(i_=0;i_<339;i_++)
      u_=(u_%2==0)?u_/=2:3*u_+1;
    while u_>1 u_=u_/2;
    v_*=u_;
  }
}

Instance Attribute Summary

Attributes inherited from Transformer

#code

Instance Method Summary collapse

Methods inherited from Transformer

#transform, #visitAddressOf, #visitArrayOf, #visitArrayOrStructInit, #visitArrow, #visitAssign, #visitBinary, #visitBody, #visitBreak, #visitCase, #visitCastedExpr, #visitCasting, #visitCharLit, #visitCommaStmt, #visitCondExpr, #visitContinue, #visitDecl, #visitDefine, #visitDeref, #visitDesignUnit, #visitDoWhile, #visitDotted, #visitElse, #visitFloatLit, #visitFor, #visitFormalArg, #visitFunctionProto, #visitGoto, #visitIdent, #visitIf, #visitInclude, #visitIndexed, #visitIntLit, #visitLabeledStmt, #visitLabelledStmt, #visitParenth, #visitPointerTo, #visitPostFixAccu, #visitPreFixAccu, #visitReturn, #visitSizeof, #visitStrLit, #visitStruct, #visitSwitch, #visitToken, #visitType, #visitTypedef, #visitUnary, #visitWhile

Constructor Details

#initialize(options = {}) ⇒ TrojanInserter

Returns a new instance of TrojanInserter.



8
9
10
# File 'lib/crokus/trojan_inserter.rb', line 8

def initialize options={}
  @options=options
end

Instance Method Details

#bodies_collect(func) ⇒ Object



82
83
84
85
86
87
88
# File 'lib/crokus/trojan_inserter.rb', line 82

def bodies_collect func
  bodies=[]
  bodies << func.body
  bodies << bodies_rec_collect(func.body)
  bodies.flatten!
  bodies
end

#bodies_rec_collect(body) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/crokus/trojan_inserter.rb', line 90

def bodies_rec_collect body
  bodies=[]
  body.each do |stmt|
    case if_=for_=while_=dowhile_=switch_=stmt
    when If
      bodies << if_.body
      if else_=if_.else
        bodies << else_.body
      end
    when For
      bodies << for_.body
    when While, DoWhile
      bodies << stmt.body
    when Switch
      bodies << switch_.cases.collect{|case_| case_.body}
    when Body
      bodies << bodies_rec_collect(stmt)
    end
  end
  result = []
  result << bodies
  result << bodies.collect{|bod| bodies_rec_collect(bod)}
  result.flatten
end

#build_trigger(func) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/crokus/trojan_inserter.rb', line 158

def build_trigger func
  args=find_int_arg(func)
  arg_names=get_arg_names(args)
  unless arg_names.size>1
    @failure_reason="not enough args of type int in func '#{func.name}' to build a trigger."
    return
  end
  arg1,arg2=arg_names.shuffle[0..1]
  puts " "*5+"|--> trigger variables are : #{arg1},#{arg2}"
  cond=Binary.new(Parenth.new(Binary.new(arg1,AND,arg2)),EQUAL,T42)
  If.new(cond,nil)
end

#build_trojan(func) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/crokus/trojan_inserter.rb', line 117

def build_trojan func
  trojan=Body.new
  anchor_var=choose_anchor(func)
  if anchor_var.nil?
    @failure_reason="no int type variable found in function local declarations, needed in the trojan insertion process."
    return
  end
  u_=Ident.new(Token.create("u_"))
  v_=Ident.new(Token.create("v_"))
  i_=Ident.new(Token.create("i_"))
  trojan << Assign.new(v_,ASSIGN,anchor_var)
  trojan<< if_trigger=build_trigger(func)
  return unless if_trigger
  trojan << Assign.new(anchor_var,ASSIGN,v_)
  ast_trojan=Crokus::Parser.new.parse(TROJAN)
  body_trojan=ast_trojan.list.first.body # root/func/body
  if_trigger.body=body_trojan
  func.body.stmts.insert(0,Decl.new(INT_TYPE,u_))
  func.body.stmts.insert(0,Decl.new(INT_TYPE,v_))
  func.body.stmts.insert(0,Decl.new(INT_TYPE,i_))
  trojan
end

#choose_anchor(func) ⇒ Object



140
141
142
143
144
145
146
# File 'lib/crokus/trojan_inserter.rb', line 140

def choose_anchor func
  # find a var of type int in func local declaration
  decls=func.body.select{|stmt| stmt.is_a? Decl}
  int_decls=decls.select{|decl| decl.type.name.is_a?(Token) && decl.type.name.kind==:int}
  vars=int_decls.map{|decl| decl.var}
  return vars.sample
end

#find_int_arg(func) ⇒ Object



171
172
173
174
175
176
177
# File 'lib/crokus/trojan_inserter.rb', line 171

def find_int_arg func
  func.args.select do |arg|
    cond1=(tok=arg.type.name).is_a?(Token) && tok.is?(:int)
    cond2=(atype=arg.type).is_a?(ArrayOf) && (tok=atype.name.name).is_a?(Token) && tok.is?(:int)
    cond1 or cond2
  end
end

#get_arg_names(args) ⇒ Object



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/crokus/trojan_inserter.rb', line 179

def get_arg_names args
  ret=[]
  args.each{|formal_arg|
    case (type=formal_arg.type)
    when ArrayOf
      if type.size.is_a?(IntLit)
        array_size=type.size.to_i
        if array_size>1
          ret << Indexed.new(formal_arg.name,ZERO_LIT)
          ret << Indexed.new(formal_arg.name,ONE_LIT)
        end
      end
    else
      ret << formal_arg.name
    end
  }
  ret.flatten!
  ret
end

#insert(ast) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/crokus/trojan_inserter.rb', line 12

def insert ast
  @nb_trojans=0
  new_ast=transform(ast)
  if @nb_trojans>0
    puts " "*1+"|--[+] insertion succeeded : #{@nb_trojans} trojan(s)"
    return new_ast
  else
    puts " "*1+"|--[?] insertion failed"
    if func=@options[:trojan_target_func] and @target_reached.nil?
      puts " "*5+"|-- no function named '#{func}' found"
    end
    if @failure_reason
      puts " "*5+"|-- #{@failure_reason}"
    end
  end
  nil
end

#insert_trojan(func) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/crokus/trojan_inserter.rb', line 56

def insert_trojan func
  if trojan=build_trojan(func)
    bodies=bodies_collect(func)
    #puts "\t#bodies = #{bodies.size}"
    target_body=bodies.sample
    stmts=target_body.stmts
    nb_decls=stmts.select{|stmt| stmt.is_a? Decl}.size
    pos=rand(nb_decls-1..stmts.size-1)+1
    target_body.stmts=stmts.insert(pos,trojan)
    return success=true
  end
  success=false
end

#new_identObject



30
31
32
33
34
35
# File 'lib/crokus/trojan_inserter.rb', line 30

def new_ident
  @tmp_id||=0
  tok=Token.create "$"+@tmp_id.to_s
  @tmp_id+=1
  Ident.new(tok)
end

#visitFunCall(fcall, args = nil) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
# File 'lib/crokus/trojan_inserter.rb', line 70

def visitFunCall fcall,args=nil
  name=fcall.name.accept(self)
  if @rename_funcs # propagate func renaming applied during visitFunction
    if @rename_funcs.keys.include?(name.to_s)
      new_name=@rename_funcs[name.to_s]
      name=Ident.create(new_name)
    end
  end
  args=fcall.args.collect{|arg| arg.accept(self)}
  FunCall.new(name,args)
end

#visitFunction(func, args = nil) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/crokus/trojan_inserter.rb', line 37

def visitFunction func,args=nil
  func_troj=super(func,args)
  if @options[:trojan_target_func].nil? or (name=@options[:trojan_target_func] and target_reached=(func.name.to_s==name))
    puts " "*1+"|--[+] func #{func.name}"
    if target_reached
      @target_reached=true
    end
    success=insert_trojan(func_troj)
    if success
      # hannah request : add a _troj to the function :
      func_troj.name=Ident.create(func.name.to_s+'_troj')
      @rename_funcs||={} # take cares of future calls to func !
      @rename_funcs[func.name.to_s]=func_troj.name.to_s
      @nb_trojans+=1
    end
  end
  func_troj
end