├── README.md └── banned_functions.py /README.md: -------------------------------------------------------------------------------- 1 | # banned_functions 2 | IDAPython script to check ELF & PE/COFF for MS SDL banned.h policy violations and set breakpoints. Microsoft no longer maintains the banned.h header file, but it contains a good list of antiquated problematic functions: 3 | 4 | bannedList = (["strcpy", "strcpyA", "strcpyW", "wcscpy", "_tcscpy", "_mbscpy", "StrCpy", 5 | "StrCpyA", "StrCpyW", "lstrcpy", "lstrcpyA", "lstrcpyW", "_tccpy", "_mbccpy", 6 | "_ftcscpy", "strcat", "strcatA", "strcatW", "wcscat", "_tcscat", "_mbscat", 7 | "StrCat", "StrCatA", "StrCatW", "lstrcat", "lstrcatA", "lstrcatW", "StrCatBuff", 8 | "StrCatBuffA", "StrCatBuffW", "StrCatChainW", "_tccat", "_mbccat", "_ftcscat", 9 | "sprintfW", "sprintfA", "wsprintf", "wsprintfW", "wsprintfA", "sprintf", "swprintf", 10 | "_stprintf", "wvsprintf", "wvsprintfA", "wvsprintfW", "vsprintf", "_vstprintf", 11 | "vswprintf", "strncpy", "wcsncpy", "_tcsncpy", "_mbsncpy", "_mbsnbcpy", "StrCpyN", 12 | "StrCpyNA", "StrCpyNW", "StrNCpy", "strcpynA", "StrNCpyA", "StrNCpyW", "lstrcpyn", 13 | "lstrcpynA", "lstrcpynW", "strncat", "wcsncat", "_tcsncat", "_mbsncat", "_mbsnbcat", 14 | "StrCatN", "StrCatNA", "StrCatNW", "StrNCat", "StrNCatA", "StrNCatW", "lstrncat", 15 | "lstrcatnA", "lstrcatnW", "lstrcatn", "gets", "_getts", "_gettws", "IsBadWritePtr", 16 | "IsBadHugeWritePtr", "IsBadReadPtr", "IsBadHugeReadPtr", "IsBadCodePtr", "IsBadStringPtr"]) 17 | 18 | This version was tested on Python 3.7.4 as Python 3.8 wasn't supported with IDAPython at the time the script was ported. 19 | 20 | -------------------------------------------------------------------------------- /banned_functions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author: Stephen Sims - @Steph3nSims 3 | Topic: IDAPython scripting - SANS SEC760 - http://www.sans.org/sec760 4 | Tested with IDA 6.7 5 | 6 | Style Improvements by: Tim Medin (B33f Supreme) 7 | 8 | Script to check an PE/COFF or ELF input file to see if it 9 | includes banned functions from MS SDL's banned.h module. If it 10 | does, it lists them out and sets breakpoints on each call. 11 | Some compilers/linker options add an intermediary jmp before 12 | reaching IAT thunk. Code compensates for either case. If you 13 | run the script a second time, it will disable the setting of 14 | all breakpoints it set on the first run. 15 | 16 | I have run this against quite a few programs 17 | and fixed a few bugs, and have had 18 | no further issues. If the script crashes, send me back the 19 | output to stephen@deadlisting.com and I will try to fix. 20 | Global flags are used to deal with issues 21 | around the different ways in which the IAT is hit, as well as 22 | xref types. 23 | 24 | e.g. Running against Microsoft's IE11 64-bit MSHTML.DLL from MS14-080. 25 | 26 | Running banned_functions.py - One moment... 27 | 28 | Found function StrCpyNW in IAT at 0x18169cd88 29 | *** calls to StrCpyNW *** 30 | => 0x180810274 - Added BP 31 | => 0x1812f10ce - Added BP 32 | => 0x1812f1fd1 - Added BP 33 | 34 | => This program calls direct to IAT. 35 | => The following banned functions were found: 36 | 37 | => StrCpyNW 38 | 39 | Finished! Breakpoints added. Run again to delete. 40 | """ 41 | import idaapi, idc, idautils 42 | 43 | checked = [] 44 | bpflag = 0 45 | codeflag = 0 46 | 47 | # Microsoft SDL banned.h list. Feel free to add/remove names. 48 | bannedList = (["strcpy", "strcpyA", "strcpyW", "wcscpy", "_tcscpy", "_mbscpy", "StrCpy", 49 | "StrCpyA", "StrCpyW", "lstrcpy", "lstrcpyA", "lstrcpyW", "_tccpy", "_mbccpy", 50 | "_ftcscpy", "strcat", "strcatA", "strcatW", "wcscat", "_tcscat", "_mbscat", 51 | "StrCat", "StrCatA", "StrCatW", "lstrcat", "lstrcatA", "lstrcatW", "StrCatBuff", 52 | "StrCatBuffA", "StrCatBuffW", "StrCatChainW", "_tccat", "_mbccat", "_ftcscat", 53 | "sprintfW", "sprintfA", "wsprintf", "wsprintfW", "wsprintfA", "sprintf", "swprintf", 54 | "_stprintf", "wvsprintf", "wvsprintfA", "wvsprintfW", "vsprintf", "_vstprintf", 55 | "vswprintf", "strncpy", "wcsncpy", "_tcsncpy", "_mbsncpy", "_mbsnbcpy", "StrCpyN", 56 | "StrCpyNA", "StrCpyNW", "StrNCpy", "strcpynA", "StrNCpyA", "StrNCpyW", "lstrcpyn", 57 | "lstrcpynA", "lstrcpynW", "strncat", "wcsncat", "_tcsncat", "_mbsncat", "_mbsnbcat", 58 | "StrCatN", "StrCatNA", "StrCatNW", "StrNCat", "StrNCatA", "StrNCatW", "lstrncat", 59 | "lstrcatnA", "lstrcatnW", "lstrcatn", "gets", "_getts", "_gettws", "IsBadWritePtr", 60 | "IsBadHugeWritePtr", "IsBadReadPtr", "IsBadHugeReadPtr", "IsBadCodePtr", "IsBadStringPtr"]) 61 | 62 | 63 | def iatCallback(addr, name, ord): # Don't care about ord, but required for enum_import_names 64 | global bpflag, codeflag, checked, bannedList # Function got a bit out of hand. Sorry. 65 | 66 | if name in bannedList and name not in checked: 67 | checked.append(name) 68 | loopflag = 0 69 | xref = XrefsTo(addr, 0) 70 | for checkXrefType in xref: 71 | if XrefTypeName(checkXrefType.type) == "Code_Near_Call" and loopflag != 1: 72 | print("\nFound function %s in IAT at 0x%08x" % (name, addr)) 73 | print("*** calls to %s ***" % name) 74 | loopflag = 1 75 | codeflag = 1 76 | xref = CodeRefsTo(addr, 1) # Ref to IAT should be of type code. 77 | for lines in xref: 78 | if check_bpt(lines) > 0: # Adding or deleting BP's 79 | idaapi.del_bpt(lines) 80 | print("=> 0x%08x - Deleted BP" % lines) 81 | else: 82 | idaapi.add_bpt(lines, 0, BPT_SOFT) 83 | enable_bpt(lines, True) 84 | checked.append(lines) 85 | print("=> 0x%08x - Added BP" % lines) 86 | bpflag = 1 87 | elif XrefTypeName(checkXrefType.type) == "Data_Read" and codeflag == 0: 88 | print("\nFound function %s in IAT at 0x%08x" % (name, addr)) 89 | print("*** calls to %s ***" % name) 90 | xref = DataRefsTo(addr) # Ref to IAT should be of type data. 91 | for line in xref: 92 | xref2 = CodeRefsTo(line, 1) 93 | for lines in xref2: 94 | if check_bpt(lines) > 0: # Adding or deleting BP's 95 | idaapi.del_bpt(lines) 96 | print("=> 0x%08x - Deleted BP" % lines) 97 | else: 98 | idaapi.add_bpt(lines, 0, BPT_SOFT) 99 | enable_bpt(lines, True) 100 | checked.append(lines) 101 | print("=> 0x%08x - Added BP" % lines) 102 | bpflag = 1 103 | elif XrefTypeName(checkXrefType.type) == "Code_Near_Jump": 104 | GOT = DataRefsTo(addr) 105 | for line in GOT: 106 | print("\n Found function %s in GOT at 0x%08x" % (name, line)) 107 | print("*** calls to %s ***" % name) 108 | codeflag = 2 109 | xref = CodeRefsTo(addr, 1) 110 | for line in xref: 111 | xref2 = CodeRefsTo(line, 1) 112 | for lines in xref2: 113 | if check_bpt(lines) > 0: 114 | idaapi.del_bpt(lines) 115 | print("=> 0x%08x - Deleted BP" % lines) 116 | else: 117 | idaapi.add_bpt(lines, 0, BPT_SOFT) 118 | enable_bpt(lines, True) 119 | checked.append(lines) 120 | print("=> 0x%08x = Added BP" % lines) 121 | bpflag = 1 122 | #elif loopflag != 1: 123 | # codeflag = 2 124 | # break 125 | else: 126 | continue #Need to compensate for other xref types. 127 | 128 | return True #Has to be here for the callback. 129 | 130 | def ToggleBreakpoints(): 131 | global bpflag, codeflag, checked, bannedList 132 | 133 | print("\nRunning banned_functions.py - One moment...") 134 | 135 | for i in range(0, idaapi.get_import_module_qty()): 136 | name = idaapi.get_import_module_name(i) 137 | idaapi.enum_import_names(i, iatCallback) 138 | 139 | if codeflag == 0 and checked != []: 140 | print("\n=> This PE/COFF program uses an intermediary jmp to IAT.") 141 | elif codeflag == 1 and checked != []: 142 | print("\n=> This PE/COFF program calls direct to IAT.") 143 | elif codeflag == 2 and checked != []: 144 | print("\n=> Looks like an ELF file. CS => PLT => *GOT.") 145 | else: 146 | print("") 147 | 148 | print("=> The following banned functions were found:\n ") 149 | 150 | for item in checked: 151 | if item in bannedList: 152 | print("=> %s" % item) 153 | 154 | if bpflag == 0 and codeflag == 1: 155 | print("\nFinished! Breakpoints deleted. Run again to add.") 156 | elif bpflag == 1 and codeflag <= 1: 157 | print("\nFinished! Breakpoints added. Run again to delete.") 158 | elif bpflag == 0 and codeflag == 0: 159 | if not checked: 160 | print("\nNo banned functions found!") 161 | else: 162 | print("\n") 163 | 164 | if __name__ == '__main__': 165 | ToggleBreakpoints() 166 | 167 | --------------------------------------------------------------------------------