Skip to content

Commit c9dcc1d

Browse files
artemdinaburgpgoodman
authored andcommitted
Windows fixes to get mcsema-disass working (lifting-bits#226)
* Windows fixes to get mcsema-disass working * Install protobuf, protoc, and python-protobuf from source * Quote IDA path to handle paths with spaces and shell=True * Set SystemRoot in env so IDAPython can still run * Add entries to windows.txt to handle a HelloWorld release build * Simplify protobuf finding for win32 and not win32 * Fix linux
1 parent 24988f9 commit c9dcc1d

File tree

5 files changed

+71
-48
lines changed

5 files changed

+71
-48
lines changed

Diff for: CMakeLists.txt

+24-34
Original file line numberDiff line numberDiff line change
@@ -13,44 +13,43 @@ if(WIN32)
1313
SET(CMAKE_EXE_LINKER_FLAGS "/LARGEADDRESSAWARE ${CMAKE_EXE_LINKER_FLAGS}")
1414
endif(WIN32)
1515

16-
set(CMAKE_MODULE_PATH "${LLVM_DIR}/cmake/modules ${CMAKE_MODULE_PATH}")
16+
set(CMAKE_MODULE_PATH "${LLVM_DIR}/cmake/modules" "${CMAKE_SOURCE_DIR}/cmake" "${CMAKE_ROOT}/Modules")
1717

1818
# Configure with the build LLVM
1919
find_package(LLVM 3.8 REQUIRED CONFIG)
2020
add_definitions(${LLVM_DEFINITIONS})
2121

22-
set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
2322
include (LLVMUtils)
2423
include (GetGitRevisionDescription)
2524

2625
# we need C++11
2726
if(NOT WIN32)
2827
# WIN32 defaults to CXX11 by default, and setting it explicitly here
2928
# confuses clang-cl, which will bail out with "unknown flag -std=g++11"
29+
30+
#FindPackage for protobuf is terrible for win32
31+
# it assumes MSVC built protobuf from a visual studio project
32+
#... we build with custom cmake, so it will never be found
33+
#... but it should work for other OSes where we install from a package
34+
3035
set(CMAKE_CXX_STANDARD 11)
31-
endif()
3236

33-
# Get protobufs.
34-
if(WIN32)
35-
# Change the slashes to Unix style or risk the wrath of invalid escape
36-
# sequences!
37-
string(REGEX REPLACE "\\\\" "/" CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR})
37+
if(APPLE)
38+
set(PROTOBUF_ROOT "${CMAKE_SOURCE_DIR}/third_party/protobuf")
39+
set(Protobuf_LIBRARIES "${PROTOBUF_ROOT}/build/lib")
40+
set(Protobuf_INCLUDE_DIR "${PROTOBUF_ROOT}/src")
41+
endif()
3842

39-
set(PROTOBUF_ROOT "${CMAKE_SOURCE_DIR}/third_party/protobuf")
40-
set(Protobuf_LIBRARIES "${PROTOBUF_ROOT}/build/libprotobuf/Release")
41-
set(Protobuf_INCLUDE_DIR "${PROTOBUF_ROOT}/src")
42-
43-
include_directories(${Protobuf_INCLUDE_DIR})
44-
link_directories(${Protobuf_LIBRARIES})
45-
elseif(APPLE)
46-
set(PROTOBUF_ROOT "${CMAKE_SOURCE_DIR}/third_party/protobuf")
47-
set(Protobuf_LIBRARIES "${PROTOBUF_ROOT}/build/lib")
48-
set(Protobuf_INCLUDE_DIR "${PROTOBUF_ROOT}/src")
49-
50-
include_directories(${Protobuf_INCLUDE_DIR})
51-
link_directories(${Protobuf_LIBRARIES})
52-
endif(WIN32)
53-
find_package(Protobuf REQUIRED)
43+
find_package(Protobuf REQUIRED)
44+
else()
45+
string(REGEX REPLACE "\\\\" "/" CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR})
46+
# on win32, manuallys set protobuf goodness
47+
set(PROTOBUF_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/include")
48+
set(PROTOBUF_LIBRARIES "${CMAKE_SOURCE_DIR}/lib/protobuf.lib")
49+
set(PROTOBUF_PROTOC_EXECUTABLE "${CMAKE_SOURCE_DIR}/bin/protoc.exe")
50+
endif()
51+
52+
include_directories(${PROTOBUF_INCLUDE_DIRS})
5453

5554
include_directories(${CMAKE_SOURCE_DIR})
5655
include_directories(${CMAKE_SOURCE_DIR}/third_party)
@@ -168,9 +167,6 @@ include_directories("${CMAKE_BINARY_DIR}")
168167
# this will make sure that the protobuf files are generated each time
169168
# the CFG.h header file is modified
170169
#
171-
# todo: use find protobuf CMake module to generate the files; this is
172-
# not easy on windows right now, since protoc is built on the fly.
173-
#
174170

175171
set(PROTOBUF_CONFIGURATION "${CMAKE_SOURCE_DIR}/mcsema/CFG/CFG.proto")
176172

@@ -180,16 +176,10 @@ set(PROTOBUF_OUTPUT_FILE_LIST
180176
"${MCSEMA_GEN_DIR}/CFG_pb2.py"
181177
)
182178

183-
if (WIN32)
184-
set(PROTOC_EXECUTABLE_PATH "${CMAKE_SOURCE_DIR}/third_party/protobuf/build/protoc/Release/protoc.exe")
185-
else ()
186-
set(PROTOC_EXECUTABLE_PATH "protoc")
187-
endif()
188-
189179
add_custom_command(
190180
OUTPUT ${PROTOBUF_OUTPUT_FILE_LIST}
191181

192-
COMMAND "${PROTOC_EXECUTABLE_PATH}" --cpp_out "${MCSEMA_GEN_DIR}" --python_out "${MCSEMA_GEN_DIR}" --proto_path "${CMAKE_SOURCE_DIR}/mcsema/CFG" "${PROTOBUF_CONFIGURATION}"
182+
COMMAND "${PROTOBUF_PROTOC_EXECUTABLE}" --cpp_out "${MCSEMA_GEN_DIR}" --python_out "${MCSEMA_GEN_DIR}" --proto_path "${CMAKE_SOURCE_DIR}/mcsema/CFG" "${PROTOBUF_CONFIGURATION}"
193183

194184
DEPENDS "${CMAKE_SOURCE_DIR}/mcsema/CFG/CFG.h"
195185
MAIN_DEPENDENCY "${PROTOBUF_CONFIGURATION}"
@@ -236,7 +226,7 @@ add_executable(mcsema-lift
236226
${CMAKE_SOURCE_DIR}/mcsema/Arch/X86/Semantics/SUB.cpp)
237227

238228
target_link_libraries(mcsema-lift
239-
protobuf
229+
${PROTOBUF_LIBRARIES}
240230
LLVMBitReader
241231
LLVMBitWriter
242232
LLVMMCDisassembler

Diff for: bootstrap.bat

+34-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,15 @@ if defined ProgramFiles(x86) (
2121
)
2222
set "PATH=%PATH%;%ProgramFiles%\7-zip"
2323

24+
REM add third-party installs to our path
25+
set "PATH=%PATH%;%MCSEMA_DIR%\bin"
26+
2427
REM sanity checks for installed software
28+
where cl >NUL 2>NUL
29+
if not %ERRORLEVEL% == 0 (
30+
echo "[!] Visual Studio (cl.exe) is not found. Please run from a Visual Studio build prompt"
31+
exit /B 1
32+
)
2533
where 7z >NUL 2>NUL
2634
if not %ERRORLEVEL% == 0 (
2735
echo [+] The 7z command is not found. Attempting to install
@@ -39,6 +47,19 @@ if not %ERRORLEVEL% == 0 (
3947
exit /B 1
4048
)
4149

50+
where python >NUL 2>NUL
51+
if not %ERRORLEVEL% == 0 (
52+
echo "[!] The python command is not found. Please install python (or add it to your PATH)"
53+
exit /B 1
54+
)
55+
56+
python -V 2>&1 | findstr /R /C:"Python 2.7" > NUL
57+
if not %ERRORLEVEL% == 0 (
58+
echo [!] Detected python != 2.7
59+
echo [!] Please install Python 2.7 and make sure it appears first in your system path
60+
exit /B 1
61+
)
62+
4263
REM This check is *SEPARATE* from the 3.8 check below for good reason
4364
REM Clang needs to be "installed" via the installer to it is available
4465
REM as a visual studio toolset. Mcsema uses it for the assembler and
@@ -134,13 +155,22 @@ REM the normal VS2013 toolset
134155
cmake.exe ^
135156
-G "%VSBUILD%" ^
136157
-DPROTOBUF_ROOT="%PROTO_DIR%" ^
158+
-DCMAKE_INSTALL_PREFIX="%MCSEMA_DIR%" ^
137159
%MCSEMA_DIR%\cmake\protobuf
138-
cmake --build . --config Release
160+
cmake --build . --config Release --target install
139161
popd
162+
163+
echo "[+] Installing protobuf for python"
164+
pushd python
165+
python setup.py build
166+
python setup.py install
140167
popd
141168

142169
popd
143170

171+
popd
172+
173+
144174
echo [+] Download and extract LLVM
145175
pushd third_party
146176
if exist llvm goto compile_llvm
@@ -190,5 +220,8 @@ cmake --build . --config Release --target install -- /maxcpucount:%NUMBER_OF_PRO
190220

191221
popd
192222

223+
echo "[+] Installing mcsema-disass"
224+
python %MCSEMA_DIR%\tools\setup.py install --user --install-scripts %MCSEMA_DIR%\bin
225+
193226
popd
194227

Diff for: tools/mcsema_disass/__main__.py

+5-12
Original file line numberDiff line numberDiff line change
@@ -102,28 +102,21 @@ def main(args=None):
102102
ret = ida.disass.execute(args, fixed_command_args)
103103

104104
# in case IDA somehow says success, but no output was generated
105-
if not os.path.isfile(args.output):
105+
if not os.path.exists(args.output) or not os.path.isfile(args.output) :
106106
sys.stderr.write("Could not generate a CFG. Try using the --log_file option to see an error log.\n")
107107
ret = 1
108108

109109
# The disassembler script probably threw an exception
110-
if 0 == os.path.getsize(args.output):
110+
elif 0 == os.path.getsize(args.output):
111111
sys.stderr.write("Generated an invalid (zero-sized) CFG. Please use the --log_file option to see an error log.\n")
112112
# remove the zero-sized file
113113
os.unlink(args.output)
114114
ret = 1
115115

116-
# in case IDA somehow says success, but no output was generated
117-
if not os.path.isfile(args.output):
118-
sys.stderr.write("Could not generate a CFG. Try using the --log_file option to see an error log.\n")
119-
ret = 1
116+
else:
117+
# assume it all went well
118+
pass
120119

121-
# The disassembler script probably threw an exception
122-
if 0 == os.path.getsize(args.output):
123-
sys.stderr.write("Generated an invalid (zero-sized) CFG. Please use the --log_file option to see an error log.\n")
124-
# remove the zero-sized file
125-
os.unlink(args.output)
126-
ret = 1
127120

128121
else:
129122
arg_parser.error("{} passed to --disassembler is not known.".format(

Diff for: tools/mcsema_disass/defs/windows.txt

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ commode 0 C N
1616
fmode 0 C N
1717

1818
#processing C runtime
19+
configthreadlocale 1 C N
20+
crtSetUnhandledExceptionFilter 1 C N
21+
XcptFilter 1 C N
22+
invoke_watson 5 C N
23+
1924
getmainargs 5 C N
2025
__getmainargs 5 C N
2126
__wgetmainargs 5 C N

Diff for: tools/mcsema_disass/ida/disass.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ def execute(args, command_args):
2525
env["HOME"] = os.path.expanduser('~')
2626
env["IDA_PATH"] = os.path.dirname(args.disassembler)
2727
env["PYTHONPATH"] = os.path.dirname(ida_dir)
28+
if "SystemRoot" in os.environ:
29+
env["SystemRoot"] = os.environ["SystemRoot"]
2830

2931
script_cmd = []
3032
script_cmd.append(ida_get_cfg_path)
@@ -41,7 +43,7 @@ def execute(args, command_args):
4143
script_cmd.extend(command_args) # Extra, script-specific arguments.
4244

4345
cmd = []
44-
cmd.append(args.disassembler) # Path to IDA.
46+
cmd.append(r'"{}"'.format(args.disassembler)) # Path to IDA.
4547
cmd.append("-B") # Batch mode.
4648
cmd.append("-S\"{}\"".format(" ".join(script_cmd)))
4749
cmd.append(args.binary)

0 commit comments

Comments
 (0)