Skip to content

SyscallToSCDG ¤

SyscallToSCDG ¤

SyscallToSCDG(scdg)

Class to map syscalls to their corresponding SCDG nodes and handle syscall behavior.

Parameters:

  • scdg

    The SCDG object to initialize the SyscallToSCDG with.

Source code in sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
def __init__(self, scdg):
    """
    Initialize the SyscallToSCDG object with the given SCDG.

    Args:
        scdg: The SCDG object to initialize the SyscallToSCDG with.
    """
    config = configparser.ConfigParser()
    config.read(sys.argv[1])
    self.config = config
    self.scdg = scdg
    self.string_resolv = config['SCDG_arg'].getboolean('string_resolve')
    self.print_syscall = config['SCDG_arg'].getboolean('print_syscall')
    self.__config_logger()

add_SysCall ¤

add_SysCall(syscall, n_args, state)

Add a syscall call to the SCDG based on the state information.

Parameters:

  • syscall

    The name of the syscall.

  • n_args

    The number of arguments for the syscall.

  • state

    The state object containing information about the execution state.

Source code in sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
def add_SysCall(self, syscall, n_args, state):
    """
    Add a syscall call to the SCDG based on the state information.

    Args:
        syscall: The name of the syscall.
        n_args: The number of arguments for the syscall.
        state: The state object containing information about the execution state.
    """
    dic = {}

    name = syscall
    sim_proc = state.inspect.simprocedure
    name = state.inspect.simprocedure_name
    state.project
    args = sim_proc.arguments or []

    regs = sim_proc.cc.ARG_REGS

    if name in ["rt_sigaction", "sigaction"]:
        state.inspect.simprocedure_result = state.solver.BVV(0, state.arch.bits)

    # Get proto of the function
    for key in self.call_sim.system_call_table.keys():
        if name in self.call_sim.system_call_table[key]:
            self.call_sim.system_call_table[key][name]

    if n_args > 0 and n_args < len(regs):
        regs = regs[:n_args]
        for reg in regs:
            try:
                reg = getattr(state.regs, reg)
            except Exception:
                reg = None
            reg = self.__proper_formating(state, reg)
            args.append(reg)

    dic["name"] = name

    # Transform if option enabled
    if self.string_resolv and args:
        args, dic = self.__check_syscall_string(syscall, state, args, dic)

    if syscall in self.FUNCTION_HANDLER:
        self.FUNCTION_HANDLER[syscall](state)

    if args:
        for i in range(len(args)):
            args[i] = self.__proper_formating(state, args[i])

    dic["args"] = args
    dic["addr_func"] = hex(state.addr)
    if len(state.globals["addr_call"]) > 0:
        dic["addr"] = hex(state.globals["addr_call"][-1])
    else:
        dic["addr"] = hex(state.addr)

    if syscall in self.FUNCTION_RETURNS:
        ret = self.FUNCTION_RETURNS[syscall](state)
        self.log.info(f"return value of {str(name)} :{str(ret)}")
        dic["ret"] = hex(ret)
    else:
        dic["ret"] = hex(0)

    id = state.globals["id"]

    if len(self.scdg) == 0:
        self.scdg.append([dic])
    else:
        if len(self.scdg[id][-1]) != 0:
            # if same address and different name, we have an inline call (call to another simprocedure used during the hook), discard !
            if (self.scdg[id][-1]["addr"] == dic["addr"] and self.scdg[id][-1]["name"] != dic["name"]):
                return

            self.scdg[id].append(dic)

        return

add_addr_call ¤

add_addr_call(state)

Add the current instruction address to the list of addresses in the global state.

Parameters:

  • state

    The state object containing information about the execution state.

Source code in sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py
557
558
559
560
561
562
563
564
565
def add_addr_call(self, state):
    """
    Add the current instruction address to the list of addresses in the global state.

    Args:
        state: The state object containing information about the execution state.
    """
    test = state.globals["addr_call"] + [state.scratch.ins_addr]
    state.globals["addr_call"] = test

add_call ¤

add_call(state)

Add a syscall call to the SCDG based on the state.

Parameters:

  • state

    The state containing information about the syscall.

Source code in sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
def add_call(self, state):
    """
    Add a syscall call to the SCDG based on the state.

    Args:
        state: The state containing information about the syscall.
    """
    name = state.inspect.simprocedure_name

    if name in self.AVOID:
        return

    sim_proc = state.inspect.simprocedure

    callee = None
    callee_arg = None
    if (sim_proc
        and sim_proc.is_syscall
        and str(sim_proc.syscall_number) in self.call_sim.system_call_table
        and self.print_syscall
    ):
        self.log.info("syscall detected")
        self.log.info(state.inspect.simprocedure_result)
        self.log.info(self.call_sim.system_call_table[str(sim_proc.syscall_number)])
        self.call_sim.system_call_table[str(sim_proc.syscall_number)]["num_args"]

    # Get definition of windows syscall (e.g.:for extraction of possible strings)
    # TODO : Optimize this heavy loop
    for key in self.call_sim.system_call_table.keys():
        if name in self.call_sim.system_call_table[key]:
            callee = self.call_sim.system_call_table[key][name]
            callee_arg = callee["arguments"]
            break
    if not callee and state.globals["loaded_libs"]:
        for k, lib in state.globals["loaded_libs"].items():
            if lib not in self.call_sim.system_call_table.keys():
                self.call_sim.ddl_loader.load_more(lib, self.call_sim.system_call_table)

    id = state.globals["id"]
    args = sim_proc.arguments if sim_proc else []

    if name:
        key_name = str(name)
        if key_name not in self.call_sim.syscall_found:
            self.call_sim.syscall_found[key_name] = 1
        else:
            self.call_sim.syscall_found[key_name] = self.call_sim.syscall_found[key_name] + 1
        self.log.info(f"Syscall found:  {str(name)}{str(args)}")

    if args:
        name_to_check =  self.scdg[id][-1]["name"]
        possibilities = { "writev": "write", "readv":"read", "socketcall": "" }
        if name_to_check == name:
            for i in range(len(args)):
                args[i] = self.__proper_formating(state, args[i])
                temp = args[i]
                try:
                    args[i] = self.if_wstring_call(state, callee_arg, args, i)
                except Exception:
                    args[i] = temp
                try:
                    args[i] = self.if_string_concrete_call(state, callee_arg, args, i)
                except Exception:
                    args[i] = temp
                try:
                    args[i] = self.if_char_call(state, callee_arg, args, i)
                except Exception:
                    args[i] = temp
                try:
                    if (self.string_resolv and callee_arg and args[i] != 0 and ("PCUNICODESTRING" in callee_arg[i]["type"])):
                        addr = self.state.memory.load(args[i]+4,4,endness=archinfo.Endness.LE)
                        args[i] = self.state.mem[addr].wstring.concrete
                except Exception:
                    args[i] = temp

            if self.string_resolv and args:
                string_func = [self.FUNCTION_STRING, self.FUNCTION_WSTRING, self.FUNCTION_CHAR]
                for i in range(len(string_func)):
                    func = string_func[i]
                    if name in func:
                        index_str = func[name]
                        try:
                            # FUNCTION_STRING
                            if i == 0:
                                string = state.mem[args[index_str]].string.concrete
                                args[index_str] = self.__decode_string(string)
                            # FUNCTION_WSTRING
                            elif i == 1:
                                string = state.mem[args[index_str]].wstring.concrete
                                args[index_str] = string
                            # FUNCTION_CHAR
                            elif i == 2:
                                string = chr(args[index_str])
                                args[index_str] = string
                        except Exception :
                            print("Error in string resolv")

            self.scdg[id][-1]["args"] = args

            if self.scdg[id][-1]["ret"] != "symbolic" and name not in self.FUNCTION_RETURNS:
                ret = -22
                try:
                    ret = state.solver.eval_one(state.inspect.simprocedure_result)
                except Exception:
                    ret = self.switch_to_claripy(state)
                self.scdg[id][-1]["ret"] = ret

            if (name == "write"
                and len(self.scdg[id]) > 1
                and self.scdg[id][-2]["name"] == "write"
                and self.scdg[id][-1]["addr"] == self.scdg[id][-1]["addr"]
                and sim_proc.use_state_arguments
            ):
                self.scdg[id][-2]["args"][1] = str(self.scdg[id][-2]["args"][1]) + str(self.scdg[id][-1]["args"][1])
                self.scdg[id].pop()

            return

        elif name_to_check in possibilities:
            if name_to_check != "socketcall":
                self.scdg[id][-1]["name"] = possibilities[name_to_check]
            elif name in self.SOCKETCALL_dic:
                self.scdg[id][-1]["name"] = name
            for i in range(len(args)):
                args[i] = self.__proper_formating(state, args[i])
            self.scdg[id][-1]["args"] = args

            try:
                ret = state.solver.eval_one(state.inspect.simprocedure_result)
            except Exception:
                ret = self.switch_to_claripy(state)
            self.scdg[id][-1]["ret"] = ret

add_call_debug ¤

add_call_debug(state)

Add a syscall call to the SCDG for debugging purposes.

Parameters:

  • state

    The state object containing information about the execution state.

Source code in sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
def add_call_debug(self, state):
    """
    Add a syscall call to the SCDG for debugging purposes.

    Args:
        state: The state object containing information about the execution state.
    """
    name = state.inspect.simprocedure_name
    sim_proc = state.inspect.simprocedure
    n_args = 0

    if name in self.AVOID:
        return

    if sim_proc:
        n_args = sim_proc.num_args

    self.add_SysCall(name, n_args, state)

if_char_call ¤

if_char_call(state, callee_arg, args, i)

Check and decode character arguments if string resolution is enabled.

Parameters:

  • state

    The state object containing information about the execution state.

  • callee_arg

    The callee arguments dictionary.

  • args

    The arguments to check and decode.

  • i

    The index of the argument to process.

Returns:

  • str

    The decoded string argument if applicable.

Source code in sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
def if_char_call(self, state, callee_arg, args, i):
    """
    Check and decode character arguments if string resolution is enabled.

    Args:
        state: The state object containing information about the execution state.
        callee_arg: The callee arguments dictionary.
        args: The arguments to check and decode.
        i: The index of the argument to process.

    Returns:
        str: The decoded string argument if applicable.
    """
    if (self.string_resolv and callee_arg and args[i] != 0 and
        ("LPCTSTR" in callee_arg[i]["type"]
        or "LPTSTR" in callee_arg[i]["type"]
        or "PTSTR" in callee_arg[i]["type"]
        or "PCTSTR" in callee_arg[i]["type"]
        or "LPCCH" in callee_arg[i]["type"]
    )):
        string = ''
        if state.solver.eval(state.memory.load(args[i]+1,1)) == 0x0:
            string = state.mem[args[i]].wstring.concrete
        else:
            string = state.mem[args[i]].string.concrete

        args[i] = self.__decode_string(string)
    return args[i]

if_string_concrete_call ¤

if_string_concrete_call(state, callee_arg, args, i)

Check and decode string arguments if string resolution is enabled.

Parameters:

  • state

    The state object containing information about the execution state.

  • callee_arg

    The callee arguments dictionary.

  • args

    The arguments to check and decode.

  • i

    The index of the argument to process.

Returns:

  • str

    The decoded string argument if applicable.

Source code in sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
def if_string_concrete_call(self, state, callee_arg, args, i):
    """
    Check and decode string arguments if string resolution is enabled.

    Args:
        state: The state object containing information about the execution state.
        callee_arg: The callee arguments dictionary.
        args: The arguments to check and decode.
        i: The index of the argument to process.

    Returns:
        str: The decoded string argument if applicable.
    """
    if (self.string_resolv and callee_arg and args[i] != 0
        and ("LPCSTR" in callee_arg[i]["type"]
        or "LPSTR" in callee_arg[i]["type"]
        or "const char*" in callee_arg[i]["type"]
        or "PSTR" in callee_arg[i]["type"]
        or "PCSTR" in callee_arg[i]["type"]
        or "LPCH" in callee_arg[i]["type"]
    )):
        string = state.mem[args[i]].string.concrete
        args[i] = self.__decode_string(string)
    return args[i]

if_wstring_call ¤

if_wstring_call(state, callee_arg, args, i)

Check and decode wide string arguments if string resolution is enabled.

Parameters:

  • state

    The state object containing information about the execution state.

  • callee_arg

    The callee arguments dictionary.

  • args

    The arguments to check and decode.

  • i

    The index of the argument to process.

Returns:

  • str

    The decoded wide string argument if applicable.

Source code in sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
def if_wstring_call(self, state, callee_arg, args, i):
    """
    Check and decode wide string arguments if string resolution is enabled.

    Args:
        state: The state object containing information about the execution state.
        callee_arg: The callee arguments dictionary.
        args: The arguments to check and decode.
        i: The index of the argument to process.

    Returns:
        str: The decoded wide string argument if applicable.
    """
    if (self.string_resolv and callee_arg and args[i] != 0 and
        ("LPCWSTR" in callee_arg[i]["type"]
        or "LPWSTR" in callee_arg[i]["type"]
        or "wchar_t*const" in callee_arg[i]["type"]
        or "OLECHAR" in callee_arg[i]["type"]
        or "PWSTR" in callee_arg[i]["type"]
        or "PCWSTR" in callee_arg[i]["type"]
        or "LPCWCH" in callee_arg[i]["type"]
    )):
        string = state.mem[args[i]].wstring.concrete

        args[i] = self.__decode_string(string)
    return args[i]

rm_addr_call ¤

rm_addr_call(state)

Remove the first address from the list of addresses in the global state if there is more than one address.

Parameters:

  • state

    The state object containing information about the execution state.

Source code in sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py
567
568
569
570
571
572
573
574
575
576
def rm_addr_call(self, state):
    """
    Remove the first address from the list of addresses in the global state if there is more than one address.

    Args:
        state: The state object containing information about the execution state.
    """
    calls = state.globals["addr_call"]
    if len(calls) > 1:
        state.globals["addr_call"] = calls[1:]

set_call_sim ¤

set_call_sim(call_sim)

Set the call simulation for the SyscallToSCDG object.

Parameters:

  • call_sim

    The call simulation object to set.

Source code in sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py
166
167
168
169
170
171
172
173
def set_call_sim(self, call_sim):
    """
    Set the call simulation for the SyscallToSCDG object.

    Args:
        call_sim: The call simulation object to set.
    """
    self.call_sim = call_sim

switch_to_claripy ¤

switch_to_claripy(state)

Switches the result to a claripy object if possible.

Parameters:

  • state

    The state object containing information about the execution state.

Returns:

  • str

    The name of the claripy object if available, else a string representation of the object.

Source code in sema_toolchain/sema_scdg/application/helper/SyscallToSCDG.py
320
321
322
323
324
325
326
327
328
329
330
331
332
333
def switch_to_claripy(self, state):
    """
    Switches the result to a claripy object if possible.

    Args:
        state: The state object containing information about the execution state.

    Returns:
        str: The name of the claripy object if available, else a string representation of the object.
    """
    stub = state.inspect.simprocedure_result
    if hasattr(stub, "to_claripy"):
        stub = stub.to_claripy()
    return stub.name if hasattr(stub, "name") else str(stub)