레이블이 hack인 게시물을 표시합니다. 모든 게시물 표시
레이블이 hack인 게시물을 표시합니다. 모든 게시물 표시

[컴][알고리즘] Depth-First Search DFS, 깊이우선 탐색




개념


각 node 가 visit 을 표시해 놓은 배열이 있다.

모든 node 에서 시작 node 로 간다.
visit 한 node 이면 다음 node 를 살펴본다.

그래서 visit 안한 node 가 있다면,
visit 안한 node 에서 시작한다.
이 node 가 start vertex 가 된다.

그러면 이 node 에서 어떤 일을 하냐면
이 node 에 붙어있는 node 들을 하나씩 보면서,
visit 안한 녀석을 찾으면
그 visit 안한 녀석을 다시 파고들어간다.

그 visit 안한 녀석을 잡고
다시, 그 node 에 붙어있는 node 들을 하나씩 보고,
visit 안한 녀석을 찾는다.

그렇게 가다보면, 결국 visit 안한 녀석을 찾을 수 없게 되고,
그러면 다시 visit 안한 녀석을 찾을 수 있는 depth 까지 돌아오게 된다.
그리고는 다시 또 쭉 파고 들어간다.

아래 예제에서는 이 visit 을 표시하는 부분과 parent 를 설정하는 부분을 python dictionary 를 이용해서 동시에 하고 있다.
parent[v] 를 통해서 parent 를 저장하고,
동시에 parent[v] 가 없다면, 아직 visit 을 안한 것으로 파악할 수 있다.




source

  • dfs_visit : visit한 vertex 를 시작점으로하고, visit 하지않은 adjVertex 를 visit 한다.
parent = {}

def dfs(vertices, adj):

    for s in vertices:  
        if s not in parent:
            parent[s] = None    # v is start vertex
            dfs_visit(vertices, adj, s)

def dfs_visit(vertices, adj, start):
    for v in adj[start]:
        if v not in parent: # not in parent means node is not visited
            parent[v] = start
            dfs_visit(vertices, adj, v)

Source from : 14. Depth-First Search (DFS), Topological Sort, MIT Open Open Course Ware

vertices

visit 해야 할 모든 vertex 들이다.

adj

한 vertex 에 연결되어 있는 vertex 들
adj[0] =[1,2,3] 
이라고 한다면, 0 에 1, 2, 3 이 연결되어 있는 것이다.(adjacent nodes)

parent

여기서 parent 는 parent 를 설정하는 역할도 하지만, 동시에 지나온 경로 path 를 알려주기도 한다. 물론 지나온 경로를 순차적으로 알기 위해서는 다른 변수를 써서 저장해야 하지만, 방문했는지 여부는 parent 로 파악할 수 있다.

dfs()

dfs_visit() 이 실제로 dfs 이며, dfs 부분은 연결되어 있지 않은 vertex 를 visit 하게 해준다. 아래와 같은 graph 를 모두 traverse 하게 해 준다.



iterative version

dfs 의 iterative 버전에 대한 설명은 여기에 해 놨는데, iterative 부분은 recursive 보다 이해하기 힘들 수도 있다.


[컴][안드로이드] deodexing 하는 방법, odex 를 다시 .dex 파일로 만들기


compile 한 소스에서 framework.apk 를 봤더니, classes.dex 파일이 없고, framework.odex 파일이 있었다. 이것은 build 옵션을 조절해 주면, 정상적인 완전한 framework.apk 가 만들어지는데, 그걸 그땐 몰랐다.[LOCAL_DEX_PREOPT 옵션관련 참고자료]

여하튼 그래서 이 odex 를 classes.dex 로 바꾸고, 이것을 .apk 와 합쳐선 완전한 framework.apk 를 만들어 보자.


baksmali -a <api_level> -x <odex_file> -d <framework_dir>

-d 는 --bootclasspath-dir <DIR> 를 이야기 한다. 보통 core.jar 의 위치를 정해주면 된다.

f:\>java -jar baksmali-1.4.2.jar -a 17 -x .\out\framework\framework.odex -d .\out\framework -o framework

.\framework
에 결과가 기록 된다. 이 안에 .smali 파일들이 있다.

이제 .\framwork 의 내용을 가지고 dex 파일을 만들어 보자.

f:\>java -jar smali.jar framework -o classes.dex

위와 같이 명령어를 실행하면, classes.dex 파일이 만들어 진다.

이제 이 .dex 를 가지고 기존의 .apk 와 합쳐서 완전한 .apk 를 만들 수 있다.

대략적으로 설명하면, .apk 를 풀고, classes.dex 를 넣고, 다시 묶고, sign 하면 된다. 이것은 apktool 로 가능하다. ref. 2 을 일단 참고하자.


References


  1. https://code.google.com/p/smali/wiki/DeodexInstructions
  2. http://noullove.tistory.com/entry/Android-ODEX-Reverse-Engineering-DE-ODEX

[컴][안드로이드] .img 압축 풀기 / .img 에서 내용 추출하기

img 추출/ img unpack


sdk/system-images/android-18/armeabi-v7a/
안에 들어있는 .img 를 추출(extract) 해 봤다.
  • system.img
  • ramdisk.img
  • userdata.img

userdata.img / system.img

simg2img

system.img 는 simg2img 로 extract 할 수 있다고 해서 시도 해 봤다. 하지만 Bad magic number 만 보여주고 풀리지 않았다.

ref. 1 에 따르면 simg2img 는 compressed ext4 img 에 쓰인다고 한다. Bad magic 이라고 뜨는 이유는 simg2img 를 이용해서 yaffs2 를 읽으려고 해서 발생한다고 한다.

하지만 아래 두 글에서 추출한 system.img 를 simg2img 를 이용해서 raw 포맷으로 변환했다.


추출한 system.img 와 sdk 의 img 가 다를 가능성이 충분히 있다.
build simg2img
  • 4.1.1_r1 이전버전
  • 이후버전
simg2img 를 만들고 나서 img 를 다음과 같이 풀 수 있다.
  • simg2img system.img system.raw.img


여하튼, 여기서는 sdk 에 존재하는 .img 를 extract 하기로 한다.

참고로, sdk .img 는 다음 경로에 존재한다.

  • android-sdk-linux/system-images/android-15/armeabi-v7a/



unyaffs2

그래서 userdata.img 와 system.img 는 yaffs file system 을 사용하기 때문에 unyaffs2 를 사용하면 된다.(unyaffs2(yaffs2utils) 홈페이지)

unyaffs2 --yaffs-ecclayout ./userdata.img ./out_directory
참고로 linux 용이다. linux 에서 samba 로 fat32 filesystem 을 mount 하고, 그곳에 out_directory 를 설정했는데, symbolic link 때문에 정상적으로 압축이 풀리지 않았다. 그래서 local 에 풀었다.

windows 용은
https://code.google.com/p/yaffey/
에서 찾을 수 있다.

ramdisk.img

rmadisk.img 를 unpack 하는 방법은 ref.2 , ref. 3 에 나와있는 설명을 정리한다. gzip 으로 되어 있어서 압축을 풀고, cpio 를 사용해서 다시 한번 unpack 하면 된다. 방법은 아래와 같다.
  1. gunzip ramdisk.img
  2. cpio -i -F ramdisk.img

See Also

  1. http://blog.naver.com/xodlftm/140180258121 : 폰에서 system.img 추출하기, adb 이용


References

  1. Mount Android emulator images
  2. http://wongfei.blog.me/10102676556
  3. ANDROID’S PARTITION IMAGES, Lindus Embedded, Embedding Open Source
  4. Mount Android emulator images - Stack Overflow



[컴][디버그] apk reversing 하기 - smali

smali 수정하기 / decompiler / apk reversing / apk 리버스 엔지니어링 / apk 해킹

apktool 을 사용해서 apk 에서 .smali 추출

apktool homepage
apktool 의 사용법은 아래와 같다.

c:\>apktool.bat d f:\a.apk f:\output_directory

하고 나서 .smali 를 수정하고, 저장한 후에 다시 .apk 로 묶어준다. 이것도 apktool 로 가능하다.

apk 로 묶기

c:\>apktool.bat b f:\output_directory

를 실행하면, 아래 두개가 생긴다.
  1. output_directory/build/apk
  2. output_directory/dist/apkFilename.apk
여기서 apkFilename.apk 를 sign 만 해주면 된다.
  1. sign 을 해주면 된다.(sign 하는 법)

install

그리고 나서 이제 설치만 하면 된다.

c:\>adb install apkFilename.apk


See Also

  1. http://i5on9i.blogspot.kr/2013/05/how-to-install-smali-syntax-file-on.html
  2. http://androidcracking.blogspot.kr/p/way-of-android-cracker-lessons.html
  3. Dalvik opcodes, Author: Gabor Paller
  4. APK 바이너리 수정후 리패키징(repack) :: GOOD to GREAT, 2015-12-16


[컴][리눅스] Android framework build


환경

  • VMWare Player + Ubuntu 12.04 LTS 64bit
  • 3GB memory
  • CPU 1 core (Intel Core i3-2100 CPU @ 3.1GHz)
  • android source version 4.3.2.1 (2013/07/31)
  • HDD : 대략 Ubuntu 용량까지 적어도 40GB 는 있어야 한다.

http://tools.android.com/build

java sdk 6

sudo add-apt-repository "deb http://archive.canonical.com/ lucid partner"
(sudo add-apt-repository ppa:webupd8team/java)
sudo apt-get update
sudo apt-get install sun-java6-jdk
sudo apt-get install oracle-java6-installer
sudo apt-get install oracle-java6-set-default


etc

sudo apt-get install python
sudo apt-get install git-core
sudo apt-get install libgl1-mesa-dri:i386

sudo apt-get install git gnupg flex bison gperf build-essential \
  zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev \
  libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-glx:i386 \
  libgl1-mesa-dev g++-multilib mingw32 tofrodos \
  python-markdown libxml2-utils xsltproc zlib1g-dev:i386


sudo ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so.1 /usr/lib/i386-linux-gnu/libGL.so


usb connection setting - for Ubuntu 12.04

http://source.android.com/source/initializing.html#configuring-usb-access

setting up ccache

clean 이나 다른 build 등을 해서 locality 가 자꾸 무너지는 경우에 유용
skip

.bash 에 output director 지정

export OUT_DIR_COMMON_BASE=<path-to-your-out-directory>
skip


repo, 2013.08.01

mkdir ~/bin
PATH=~/bin:$PATH
curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo
chmod +x ~/bin/repo

작업 디렉토리

mkdir JELLY_SOURCE
cd JELLY_SOURCE

  • master's repo
    • repo init -u https://android.googlesource.com/platform/manifest
  • branch's repo
    • repo init -u https://android.googlesource.com/platform/manifest -b android-4.0.1_r1
    • ref. 4 에서 branch version 을 알 수 있다.

이름, email 입력

repo sync

vmware 에서 약 2시간 정도 걸렸다.
3GB memory
core 2

setting up build environment

source build/envsetup.sh


apk 파일을 odex 없이 만드려면[ref. 5]

  • 모든 apk 를 odex 없이 만드려면
    • make WITH_DEXPREOPT=true 를 하던지,
    • build/core/package.mk 에 LOCAL_DEX_PREOPT := false 를 true 로 수정하면 된다.
  • 개개의 apk 에 대해 설정하려면
    • packages/apps/Contacts/Android.mk 에 LOCAL_DEX_PREOPT := false 를 추가 하면 된다.


start to build

빌드하는데 약 30GB 정도가 필요하다고 한다.

source /etc/profile.d/jdk.sh  # $JAVA_HOME 설정

make + make sdk 를 하지 않고, make sdk_win 만 build 를 하게 되면, error 3 이 발생한다. 그래서 한 번 full build 를 해주고, clean 을 하지 않을 상태로 make sdk 를 먼저 해주고, make sdk_win 을 해줘야 한다. 그러므로,

lunch full-eng
make -j1 (약 5시간, -j 옵션은 core 가 여러개 일때 필요하다. 여기선 참고로 적는다.)
               make -j2 (약 4시간)

lunch sdk-eng
make -j1 sdk (약 1시간)
make -j1 sdk_win


============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.3.2.1.000.000
TARGET_PRODUCT=sdk
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a
TARGET_CPU_VARIANT=generic
HOST_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.5.0-37-generic-x86_64-with-Ubuntu-12.04-precise
HOST_BUILD_TYPE=release
BUILD_ID=OPENMASTER
OUT_DIR=out
============================================


error 1

Module 'bluetooth-health'in PRODUCT_PACKAGES has nothing to install!
>> Enforce no nonexistent modules in PRODUCT_PACKAGES for sdk builds

Modify /core/main.mk diff

error 2

## Running sdk/eclipse/scripts/create_all_symlinks.sh
### Starting tools/base: gradlew publishLocal
sdk/eclipse/scripts/create_all_symlinks.sh: line 285: cd: tools/base: No such file or directory
make: *** [out/host/linux-x86/obj/EXECUTABLES/monitor_intermediates/monitor] Error 1

repo init -u https://android.googlesource.com/platform/manifest -g all,tools
repo sync

error 3

No rule to make target `out/host/linux-x86/bin/emugen', needed by `out/host/windows-x86/obj/STATIC_LIBRARIES/lib_renderControl_dec_intermediates/renderControl_dec.cpp'

>> https://groups.google.com/forum/#!topic/android-building/Zmnrf6DRgjg

lunch full-eng
make

lunch sdk-eng
make sdk
make win_sdk


결과


SRC_DIR/out/host/windows/sdk/android-sdk_eng.namh_windows.zip


full build 결과
...
+ ENABLE_SPARSE_IMAGE=
+ '[' out/target/product/generic/cache = -s ']'
+ '[' 6 -ne 5 -a 6 -ne 6 ']'
+ SRC_DIR=out/target/product/generic/cache
+ '[' '!' -d out/target/product/generic/cache ']'
+ OUTPUT_FILE=out/target/product/generic/cache.img
+ EXT_VARIANT=ext4
+ MOUNT_POINT=cache
+ SIZE=69206016
+ FC=out/target/product/generic/root/file_contexts
+ case $EXT_VARIANT in
+ '[' -z cache ']'
+ '[' -z 69206016 ']'
+ '[' -n out/target/product/generic/root/file_contexts ']'
+ FCOPT='-S out/target/product/generic/root/file_contexts'
+ MAKE_EXT4FS_CMD='make_ext4fs  -S out/target/product/generic/root/file_contexts -l 69206016 -a cache out/target/product/generic/cache.img out/target/product/generic/cache'
+ echo make_ext4fs -S out/target/product/generic/root/file_contexts -l 69206016 -a cache out/target/product/generic/cache.img out/target/product/generic/cache
make_ext4fs -S out/target/product/generic/root/file_contexts -l 69206016 -a cache out/target/product/generic/cache.img out/target/product/generic/cache
+ make_ext4fs -S out/target/product/generic/root/file_contexts -l 69206016 -a cache out/target/product/generic/cache.img out/target/product/generic/cache
Creating filesystem with parameters:
    Size: 69206016
    Block size: 4096
    Blocks per group: 32768
    Inodes per group: 4224
    Inode size: 256
    Journal blocks: 1024
    Label: 
    Blocks: 16896
    Block groups: 1
    Reserved block group size: 7
Created filesystem with 11/4224 inodes and 1302/16896 blocks
+ '[' 0 -ne 0 ']'
out/target/product/generic/cache.img maxsize=70654848 blocksize=2112 total=69206016 reserve=713856

Installed file list: out/target/product/generic/installed-files.txt
Target system fs image: out/target/product/generic/obj/PACKAGING/systemimage_intermediates/system.img
Running:  mkuserimg.sh out/target/product/generic/system out/target/product/generic/obj/PACKAGING/systemimage_intermediates/system.img ext4 system 576716800 out/target/product/generic/root/file_contexts
+ echo 'in mkuserimg.sh PATH=out/host/linux-x86/bin/:/usr/lib/jvm/java-6-oracle/bin:/home/namh/jelly_src/out/host/linux-x86/bin:/home/namh/jelly_src/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin:/home/namh/jelly_src/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/bin:/home/namh/jelly_src/prebuilts/gcc/linux-x86/mips/mipsel-linux-android-4.7/bin:/home/namh/jelly_src/development/emulator/qtools:/home/namh/jelly_src/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin:/home/namh/jelly_src/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/bin:/home/namh/jelly_src/development/scripts:/home/namh/jelly_src/prebuilts/devtools/tools:/home/namh/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/java-6-oracle/bin:/usr/lib/jvm/java-6-oracle/db/bin:/usr/lib/jvm/java-6-oracle/jre/bin'
in mkuserimg.sh PATH=out/host/linux-x86/bin/:/usr/lib/jvm/java-6-oracle/bin:/home/namh/jelly_src/out/host/linux-x86/bin:/home/namh/jelly_src/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin:/home/namh/jelly_src/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/bin:/home/namh/jelly_src/prebuilts/gcc/linux-x86/mips/mipsel-linux-android-4.7/bin:/home/namh/jelly_src/development/emulator/qtools:/home/namh/jelly_src/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin:/home/namh/jelly_src/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/bin:/home/namh/jelly_src/development/scripts:/home/namh/jelly_src/prebuilts/devtools/tools:/home/namh/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/java-6-oracle/bin:/usr/lib/jvm/java-6-oracle/db/bin:/usr/lib/jvm/java-6-oracle/jre/bin
+ ENABLE_SPARSE_IMAGE=
+ '[' out/target/product/generic/system = -s ']'
+ '[' 6 -ne 5 -a 6 -ne 6 ']'
+ SRC_DIR=out/target/product/generic/system
+ '[' '!' -d out/target/product/generic/system ']'
+ OUTPUT_FILE=out/target/product/generic/obj/PACKAGING/systemimage_intermediates/system.img
+ EXT_VARIANT=ext4
+ MOUNT_POINT=system
+ SIZE=576716800
+ FC=out/target/product/generic/root/file_contexts
+ case $EXT_VARIANT in
+ '[' -z system ']'
+ '[' -z 576716800 ']'
+ '[' -n out/target/product/generic/root/file_contexts ']'
+ FCOPT='-S out/target/product/generic/root/file_contexts'
+ MAKE_EXT4FS_CMD='make_ext4fs  -S out/target/product/generic/root/file_contexts -l 576716800 -a system out/target/product/generic/obj/PACKAGING/systemimage_intermediates/system.img out/target/product/generic/system'
+ echo make_ext4fs -S out/target/product/generic/root/file_contexts -l 576716800 -a system out/target/product/generic/obj/PACKAGING/systemimage_intermediates/system.img out/target/product/generic/system
make_ext4fs -S out/target/product/generic/root/file_contexts -l 576716800 -a system out/target/product/generic/obj/PACKAGING/systemimage_intermediates/system.img out/target/product/generic/system
+ make_ext4fs -S out/target/product/generic/root/file_contexts -l 576716800 -a system out/target/product/generic/obj/PACKAGING/systemimage_intermediates/system.img out/target/product/generic/system
Creating filesystem with parameters:
    Size: 576716800
    Block size: 4096
    Blocks per group: 32768
    Inodes per group: 7040
    Inode size: 256
    Journal blocks: 2200
    Label: 
    Blocks: 140800
    Block groups: 5
    Reserved block group size: 39
Created filesystem with 1156/35200 inodes and 64194/140800 blocks
+ '[' 0 -ne 0 ']'
Install system fs image: out/target/product/generic/system.img
out/target/product/generic/system.img+ maxsize=588791808 blocksize=2112 total=576716800 reserve=5947392



make sdk 결과

Package SDK Stubs: out/target/common/obj/PACKAGING/android_jar_intermediates/android.jar
Checking API: uiautomator-checkapi-last
Checking API: uiautomator-checkapi-current
target Java: android_uiautomator (out/target/common/obj/JAVA_LIBRARIES/android_uiautomator_intermediates/classes)
Copying: out/target/common/obj/JAVA_LIBRARIES/android_uiautomator_intermediates/classes-jarjar.jar
Copying: out/target/common/obj/JAVA_LIBRARIES/android_uiautomator_intermediates/emma_out/lib/classes-jarjar.jar
Copying: out/target/common/obj/JAVA_LIBRARIES/android_uiautomator_intermediates/classes.jar
target Static Jar: android_uiautomator (out/target/common/obj/JAVA_LIBRARIES/android_uiautomator_intermediates/javalib.jar)
Package android-support-v4.jar: out/target/common/obj/PACKAGING/android-support-v4_intermediates/android-support-v4.jar
target Static Jar: android-support-v7-gridlayout (out/target/common/obj/JAVA_LIBRARIES/android-support-v7-gridlayout_intermediates/javalib.jar)
Package android-support-v7-gridlayout.jar: out/target/common/obj/PACKAGING/android-support-v7-gridlayout_intermediates/android-support-v7-gridlayout.jar
target Static Jar: android-support-v7-appcompat (out/target/common/obj/JAVA_LIBRARIES/android-support-v7-appcompat_intermediates/javalib.jar)
Package android-support-v7-appcompat.jar: out/target/common/obj/PACKAGING/android-support-v7-appcompat_intermediates/android-support-v7-appcompat.jar
target Static Jar: android-support-v7-mediarouter (out/target/common/obj/JAVA_LIBRARIES/android-support-v7-mediarouter_intermediates/javalib.jar)
Package android-support-v7-mediarouter.jar: out/target/common/obj/PACKAGING/android-support-v7-mediarouter_intermediates/android-support-v7-mediarouter.jar
Package android-support-v13.jar: out/target/common/obj/PACKAGING/android-support-v13_intermediates/android-support-v13.jar
Import includes file: out/host/linux-x86/obj/EXECUTABLES/atree_intermediates/import_includes
host C++: atree <= build/tools/atree/atree.cpp
host C++: atree <= build/tools/atree/files.cpp
host C++: atree <= build/tools/atree/fs.cpp
Export includes file: build/tools/atree/Android.mk -- out/host/linux-x86/obj/EXECUTABLES/atree_intermediates/export_includes
host Executable: atree (out/host/linux-x86/obj/EXECUTABLES/atree_intermediates/atree)
Install: out/host/linux-x86/bin/atree
Import includes file: out/host/linux-x86/obj/EXECUTABLES/line_endings_intermediates/import_includes
host C: line_endings <= development/tools/line_endings/line_endings.c
Export includes file: development/tools/line_endings/Android.mk -- out/host/linux-x86/obj/EXECUTABLES/line_endings_intermediates/export_includes
host Executable: line_endings (out/host/linux-x86/obj/EXECUTABLES/line_endings_intermediates/line_endings)
Install: out/host/linux-x86/bin/line_endings
Package SDK: out/host/linux-x86/sdk/android-sdk_eng.namh_linux-x86.zip
SDK: warning: including GNU target out/target/product/generic/system/lib/libgccdemangle.so

make win_sdk

====== [Windows SDK] Build android-sdk_eng.namh_windows ======

MAIN_SDK_NAME: android-sdk_eng.namh_linux-x86
WIN_SDK_NAME : android-sdk_eng.namh_windows
WIN_SDK_DIR  : out/host/windows/sdk
WIN_SDK_ZIP  : out/host/windows/sdk/android-sdk_eng.namh_windows.zip
Windows SDK generated at out/host/windows/sdk/android-sdk_eng.namh_windows.zip

====== [Windows SDK] Done ======

images

~/WORKING_DIRECTORY/out/target/product/generic
빌드가 끝나면, 위의 경로에서 .img 들을 찾을 수 있다.

  • system.img : 
    • /home/namh/jelly_src/out/target/product/generic/system 의 묶음
  • ramdisk.img
    • /home/namh/jelly_src/out/target/product/generic/root
  • userdata.img
    • /home/namh/jelly_src/out/target/product/generic/data
    • /home/namh/jelly_src/out/target/common/obj/APPS

참고로, 이 .img 를 unpack 할 수 있다.(참고: http://i5on9i.blogspot.kr/2013/08/img-img.html)


system.img 에서 apk 들을 보면, .odex 파일과 .apk 파일로 나눠져 있다. 그런데 이 녀석들을 compile option 을 줘서 .apk 파일 하나로 생성되게 할 수 있다. 물론 빌드하기 전에 옵션을 만져줘야 한다.[ref. 5][ref. 6]


build process[ref. 7, 8]



emulator 에서 image 실행

make full-eng 만 한 상태라면 아래 경로에 있을 것이다.[ref. 1]
~/WORKING_DIRECTORY/out/target/product/generic
이 .img 들을 가지고 아래 처럼 하면, emulator 로 실행할 수 있다.
<android_sdk>\tools\emulator.exe -system system.img -ramdisk ramdisk.img -data userdata.img
see also : http://i5on9i.blogspot.kr/2013/08/command-avd.html


error - Segmentation fault
namh@ubuntu:~/jelly_src$ ./out/host/linux-x86/bin/emulator -system out/target/product/generic -kernel prebuilts/qemu-kernel/arm/kernel-qemu -verbose
emulator: WARNING: Please note that the -system option should now be used to point to the initial
system image (like the obsolete -image option). To point to the system directory
please now use '-sysdir ' instead.

emulator: autoconfig: -system out/target/product/generic/system.img
emulator: autoconfig: -ramdisk out/target/product/generic/ramdisk.img
emulator: autoconfig: -datadir out/target/product/generic
emulator: autoconfig: -data out/target/product/generic/userdata-qemu.img
emulator: Found target ABI=armeabi-v7a, architecture=arm
emulator: Found target API level: 18
emulator: using core hw config path: out/target/product/generic/hardware-qemu.ini
emulator: autoconfig: -skin HVGA
emulator: autoconfig: -skindir (null)
emulator: keyset loaded from: /home/namh/.android/default.keyset
emulator: skin name 'HVGA' aliased to '320x480'
emulator: found magic skin width=320 height=480 bpp=16

emulator: Using initial system image: out/target/product/generic/system.img
emulator: WARNING: system partition size adjusted to match image file (550 MB > 200 MB)

emulator: autoconfig: -initdata out/target/product/generic/userdata.img
emulator: WARNING: data partition size adjusted to match image file (550 MB > 200 MB)

emulator: autoconfig: -cache out/target/product/generic/cache.img
emulator: autoconfig: -sdcard out/target/product/generic/system.img
emulator: Physical RAM size: 96MB

emulator: Found target ABI=armeabi-v7a
emulator: Auto-config: -qemu -cpu cortex-a8
Content of hardware configuration file:
  hw.cpu.arch = arm
  hw.cpu.model = cortex-a8
  hw.ramSize = 96
  hw.screen = touch
  hw.mainKeys = yes
  hw.trackBall = yes
  hw.keyboard = no
  hw.keyboard.lid = no
  hw.keyboard.charmap = qwerty2
  hw.dPad = yes
  hw.gsmModem = yes
  hw.gps = yes
  hw.battery = yes
  hw.accelerometer = yes
  hw.audioInput = yes
  hw.audioOutput = yes
  hw.sdCard = yes
  hw.sdCard.path = out/target/product/generic/system.img
  disk.cachePartition = yes
  disk.cachePartition.path = out/target/product/generic/cache.img
  disk.cachePartition.size = 66m
  hw.lcd.width = 320
  hw.lcd.height = 480
  hw.lcd.depth = 16
  hw.lcd.density = 160
  hw.lcd.backlight = yes
  hw.gpu.enabled = no
  hw.camera.back = emulated
  hw.camera.front = none
  vm.heapSize = 16
  hw.sensors.proximity = yes
  hw.sensors.magnetic_field = yes
  hw.sensors.orientation = yes
  hw.sensors.temperature = yes
  kernel.path = prebuilts/qemu-kernel/arm/kernel-qemu
  kernel.parameters =  android.checkjni=1
  disk.ramdisk.path = out/target/product/generic/ramdisk.img
  disk.systemPartition.initPath = out/target/product/generic/system.img
  disk.systemPartition.size = 550m
  disk.dataPartition.path = out/target/product/generic/out/target/product/generic/userdata-qemu.img
  disk.dataPartition.size = 550m
  avd.name = 
.
QEMU options list:
emulator: argv[00] = "./out/host/linux-x86/bin/emulator64-arm"
emulator: argv[01] = "-android-hw"
emulator: argv[02] = "out/target/product/generic/hardware-qemu.ini"
Concatenated QEMU options:
 ./out/host/linux-x86/bin/emulator64-arm -android-hw out/target/product/generic/hardware-qemu.ini
emulator: registered 'boot-properties' qemud service
emulator: nand_add_dev: system,size=0x22600000,initfile=out/target/product/generic/system.img
emulator: mapping 'system' NAND image to /tmp/android-namh/emulator-O2f423
WARNING: Data partition already in use. Changes will not persist!
emulator: nand_add_dev: userdata,size=0x22600000
emulator: mapping 'userdata' NAND image to /tmp/android-namh/emulator-KDwBdW
emulator: registered 'boot-properties' qemud service
emulator: Adding boot property: 'dalvik.vm.heapsize' = '16m'
emulator: Adding boot property: 'qemu.sf.lcd_density' = '160'
emulator: Adding boot property: 'qemu.hw.mainkeys' = '1'
emulator: Adding boot property: 'qemu.sf.fake_camera' = 'back'
emulator: nand_add_dev: cache,size=0x4200000,file=out/target/product/generic/cache.img
emulator: Initializing hardware OpenGLES emulation support
Segmentation fault (core dumped)

emulator 대신에 emulator-arm 으로 실행했더니 됐다. 이외에도 여러가지 case 가 있는 듯 하다. 아래 글을 참고 하자.



error - black screen

emulator 가 실행이 되지만, 계속 black screen 에 머물러 있다.

gingerbread 에서는 gingerbread branch 에서는 emulator 가 동작하지 않고, 이후 source version 에서 동작이 되었다고 한다. 이런 사례로 미루어 볼 때 최신 source 를 빌드하고 나서 emulator 가 동작안할 가능성도 있다.
http://source.android.com/source/known-issues.html
이 경우 동작하는 sdk 를 다운 받아서 emulator 를 실행해야 하는 듯 하다. 하지만 2013.8.05 일 최신 버전 master 를 다운받아서 나온 img 들은 최신 sdk 의 emulator 에서 동작하지 않았다.

emulator 에서 동작하는 img 를 만들어 보고 싶다면, release 된 버전을 가지고 compile 을 해 보는 것이 좋을 듯 하다. 참고로 emulator 는
lunch full-eng
를 해서 나온 .img 만 가능하다고 한다.[Choose a Target, Android Dev. Document]

근데, ref. 9 를 보면
  • lunch sdk_x86-eng
  • make sdk 
만 해서 emulator 를 build 하는 듯 하다.



기타


커널빌드
커널만 repo 에서 받아와서 빌드할 수 있다.(Building Kernels, android document)
full source 를 받았다면, 아래 경로에 source 가 있다.
device/<vendor>/<name> :
 /home/namh/jelly_src/device/samsung/maguro

빌드한 소스를 eclipse 와 연결하는 방법



See Also

  1. Tutorial: Android Internals - Building a Custom ROM, Pt. 1 of 2


References

  1. http://www.rodneybeede.com/How_to_build_an_Android_ROM_from_source.html
  2. Building and Testing Android Source, 2013년 2월
  3. 안드로이드 goldfish 디버그하기, 2011년 2월
  4. Codenames, Tags, and Build Numbers, Android branch 와 안드로이드 버전 이름 정보를 알 수 있다.
  5. Android 빌드 시 preload app 을 odex 없이 빌드하기., 2012년 1월 4일
  6. https://groups.google.com/forum/#!topic/android-building/oWrcDTkpH8g, 2010년
  7. http://developer.android.com/tools/building/index.html#detailed-build
  8. http://www.androes.com/176
  9. Android on x86: Understanding Android Device Emulation By Iggy Krajci and Darren Cummings, September 17, 2013



[컴][Hack][디버그] disassembly code 분석 방법 - 3



RtlInsertElementGenericTable.


56DF4FE6  /. 55             PUSH EBP
56DF4FE7  |. 8BEC           MOV EBP,ESP
56DF4FE9  |. 57             PUSH EDI 56DF4FEA  |. 8B7D 08        MOV EDI,DWORD PTR SS:[EBP+8] ; edi = *(ebp + 8)56DF4FED  |. 8D45 08        LEA EAX,DWORD PTR SS:[EBP+8]  ; eax = ebp + 8
56DF4FF0  |. 50             PUSH EAX                                  ; 2nd parameter56DF4FF1  |. FF75 0C        PUSH DWORD PTR SS:[EBP+C]  ; 1st parameter
56DF4FF4  |. E8 4DE1FDFF    CALL ntdll_1.56DD3146
56DF4FF9  |. 50             PUSH EAX
56DF4FFA  |. FF75 08        PUSH DWORD PTR SS:[EBP+8]
56DF4FFD  |. FF75 14        PUSH DWORD PTR SS:[EBP+14]
56DF5000  |. FF75 10        PUSH DWORD PTR SS:[EBP+10]
56DF5003  |. FF75 0C        PUSH DWORD PTR SS:[EBP+C]
56DF5006  |. 57             PUSH EDI
56DF5007  |. E8 0A000000    CALL ntdll_1.RtlInsertElementGenericTableFull>
56DF500C  |. 5F             POP EDI
56DF500D  |. 5D             POP EBP
56DF500E  \. C2 1000        RETN 10

일반적으로 PUSH 가 쓰이는 곳

  1. register 를 사용하기 위해, register 가 가지고 있는 값을 stack 에 보관 할 때,(보통 이 경우에는 push 로 register A 의 값을 저장했다고, 함수 끝날 때 다시 pop 을 해서 해당 register A 에 값을 복원한다.)
  2. function call 에서 parameter 를 넘길 때
  3. 아주 가끔, register 의 값을 복사할 때, push 하고 바로 pop 을 통해 register 의 값을 다른 register 로 복사한다.
std calling convention 에서는 a(1,2,3) 이라는 함수가 있으면 3, 2, 1 의 순으로 parameter 가 stack 에 push 된다.

ntdll_1.56DD3146

56DD3146   $ 8BFF           MOV EDI,EDI ; 의미 없다. windows 에서 trapping 을 위한 mark 이다. 56DD3148   . 55             PUSH EBP
56DD3149   . 8BEC           MOV EBP,ESP
56DD314B   . 56             PUSH ESI
56DD314C   . 8B37           MOV ESI,DWORD PTR DS:[EDI] ; esi = *edi, (첫번째 element)
56DD314E   . 85F6           TEST ESI,ESI
56DD3150   . 0F84 5E1F0200  JE ntdll_1.56DF50B4
56DD3156   > 8D46 18        LEA EAX,DWORD PTR DS:[ESI+18]
56DD3159   . 50             PUSH EAX                                ; 3rd parameter56DD315A   . FF75 08        PUSH DWORD PTR SS:[EBP+8] ; 2nd parameter56DD315D   . 57             PUSH EDI                              ; 1st parameter56DD315E   . FF57 18        CALL DWORD PTR DS:[EDI+18] 56DD3161   . 85C0           TEST EAX,EAX             ; callback function 의 return value 를 test 하고56DD3163   . 0F84 8D200200  JE ntdll_1.56DF51F6 ; '0' 이면 jump 한다.56DD3169   . 83F8 01        CMP EAX,1                ; callback function 의 return value 를 '1' 과 비교
56DD316C   . 0F84 93200200  JE ntdll_1.56DF5205 ;  '1' 이 맞으면 jump
56DD3172   . 33C0           XOR EAX,EAX            ; return value 가 '1' or '0' 이 아닐 때, eax 를 0 으로56DD3174   . 40             INC EAX                    ; eax 를 '1'로 , 이 함수의 return value 는 '1' 이 될 것이다.
56DD3175   > 8B4D 0C        MOV ECX,DWORD PTR SS:[EBP+C] ; ecx = 2nd parameter from caller of ntdll.56DD3146
56DD3178   . 8931           MOV DWORD PTR DS:[ECX],ESI         ;  *ecx = esi
56DD317A   > 5E             POP ESI
56DD317B   . 5D             POP EBP
56DD317C   . C2 0800        RETN 8
56DF51F6 > 8B46 04       MOV EAX,DWORD PTR DS:[ESI+4]; eax = *(esi + 4)
56DF51F9 . 85C0             TEST EAX,EAX
56DF51FB . 75 79            JNZ SHORT ntdll_1.56DF527656DF51FD . 6A 02            PUSH 2
56DF51FF > 58                POP EAX
56DF5200 .^E9 70DFFDFF JMP ntdll_1.56DD3175

56DF5205   > 8B46 08        MOV EAX,DWORD PTR DS:[ESI+8] ; eax = *(esi + 8)
56DF5208   . 85C0           TEST EAX,EAX
56DF520A   . 75 6A          JNZ SHORT ntdll_1.56DF5276
56DF520C   . 6A 03          PUSH 3
56DF520E   .^EB EF          JMP SHORT ntdll_1.56DF51FF


56DF5276   > 8BF0             MOV ESI,EAX
56DF5278   .^E9 D9DEFDFF    JMP ntdll_1.56DD3156

이 함수에서 edi 에 어떤 값을 할당하는 부분이 전혀 없다. 그런데 call dword ptr [edi+18] 을 하는 것은 함수가 호출되기 이전에 이미 edi 에 어떤 값을 할당했다는 것을 알 수 있다.
그렇다면, 어떤 calling convention 이 EDI 를 통해 parameter 를 전달하는 것일까? 안타깝게 그런 calling convention 은 없다. 이 경우에는 static 일 가능성이 있다.
static 이 아닌 경우에 컴파일러는 보통 "알 수 없는 caller" 를 위해서 calling convention 이 잘 유지시키지만, 함수가 static 을 사용하면서 현재 object 파일에 대해 명백하게 local 일 때는 calling convention 을 유지 하지 않기도 한다. 위의 함수의 경우처럼 register 를 이용해서 parameter 를 전달하기도 한다.
잘 보면 함수를 호출하는 caller 쪽에서는 push 를 통해 parameter 를 stack 에 넣고 있긴 하지만, 실제로 callee 쪽에서 그냥 register 의 값을 가져와서 사용해 버린다.
RETN 8
를 통해서 8 bytes 의 paramter 를 전달받는 다는 것을 알 수 있고, 또, EDI 를 통해서 parameter 를 전달 받았으니, 총 3개의 parameter 를 전달받았다.
EDI 는 caller 쪽에서 확인을 해 보면 아래와 같다.
MOV EDI,DWORD PTR SS:[EBP+8] ; edi = *(ebp + 8)
아마도 ebp+8 이니까 1st parameter 일 것이다.

working-set tuning

JE ntdll_1.56DF50B4
위의 주소처럼 function 이 현재 주소 보다 멀리 떨어져서 분포되어 있는 경우가 있다. 이것은 windows 의 memory management 이슈 때문이다.
executable module 을 만들 때, 가장 중요한 점 중에 하나는 모듈을 어떤 식으로 배치시키는 것이냐 이다. 그래서 모듈이 메모리로 load 될 때 물리적인 memory 를 가장 적게 사용하는 쪽으로 배치를 시키려 한다. 이것을 working-set tuning 이라고 부른다.
Windows 는 실제 사용하는 영역에 대해서만 physical memory 를 할당하기 때문에 잘 쓰이는 code 영역(popular code sections)은 모듈의 맨 앞쪽 부분에 있게 되고 잘 안 쓰이는 code들은 뒤쪽으로 놓이게 된다.
그러므로 위에서 보이는 56DF50B4 는 우리가 분석하고 있는 code 주소인 56DD3146 보다 훨씬 뒤의 주소이기 때문에, 이 녀석은 훨씬 덜 쓰이는 녀석이라고 추측해 볼 수 있다. 이 녀석을 대충 따라가 보면 알겠지만, error handling code 이다. error handling code는 실제로 error 가 발생했을 때만 쓰이기에 보통 이렇게 뒤쪽에 놓일 가능성이 높다.

CALL DWORD PTR DS:[EDI+18]

CALL DWORD PTR DS:[EDI+18]
EDI 는 이전 글에서 봤던 structure 이다.(RtlInsertElementGenericTable 이 Generic Table 을 insert 하기 위한 것이니까 parameter 중에 하나는 확실히 generic table 의 structure 일 것이다.) 그런데 이 녀석의 7 번째 member (EDI+18) 를 call 하는 것을 통해 이 녀석이 함수의 주소인 것을 알 수 있다. 그러면 table 은 아래와 같아진다.

ecx(= ebp+8) param 1 offset + 0 member 1 pointer
ecx+4 offset + 4 member 2 pointer
offset + 8 member 3 pointer
offset + c member 4 pointer
offset + 10 member 5
offset + 14 member 6 element 총 개수
offset + 18 member 7 function pointer
offset + 1c member 8
offset + 20 member 9
offset + 24 member 10

RtlInitializeGenericTable 를 보면 아래처럼 memeber 7 은 2번째 parameter 에서 얻어온 값이다.
mov ecx, dword ptr ss:[ebp+c]
mov dword ptr ds:[eax+18], ecx
그렇다면 우리가 GenericTable 을 초기화 할 때 넘겨주는 함수 포인터이기에, user-defined function pointer 가 될 것이다.

이 user-defined 함수를 호출할 때 3개의 parameter 를 넘겨주는데, 첫 번째는 table data structure 이고, 2번 째는 이 함수(우리가 분석중인)로 넘어온 parameter 이고, 3번째는 ESI+18 이다.
56DD3156 > 8D46 18 LEA EAX,DWORD PTR DS:[ESI+18]
56DD3159 . 50          PUSH EAX ; 3rd parameter56DD315A . FF75 08   PUSH DWORD PTR SS:[EBP+8] ; 2nd parameter56DD315D . 57         PUSH EDI ; 1st parameter56DD315E . FF57 18 CALL DWORD PTR DS:[EDI+18]
ESI 는 "EDI 가 가진 address 가 가리키는 값(*edi)"을 가지고 있다. 위의 table 의 구조를 가지는 structure 이다.(앞으로 이 structure 를 TS 라고 부르자.)
이 3개의 parameter 가 어떤 값이 될지는 밑에서 얘기하자.


56DF51F6

56DF51F6를 살펴보면,
ESI+4(offset+4)의 값(value)이
  • '0' 이 아니면,
    1. ESI 로 값을 load 하고 : esi = *(esi+4)
    2. callback 함수를 call 하는 부분으로 돌아간다.
  • '0' 이면
    1. 호출했던 곳으로 돌아간다.
이 모습은 linked list 를 traverse 하면서 user-defined function 을 호출하는 것처럼 보인다.

3rd parameter 로 ESI+18 을 넘겼다. ESI 가 TS 의 root 를 가지고 있기 때문에, TS의 크기는 적어도 0x1c(0x18 + 4) bytes 이상일 것이라 추측할 수 있다.


JE ntdll_1.56DF5205
JE ntdll_1.56DF5205
esi+8 값을 TEST 해서 
  • esi+8 이 '0' 이면 '3' 을 return 한다.
  • esi+8 이 '0' 이 아니면, esi 에 esi+8 값을 넣고 다시 callback 함수를 호출
esi + 8 은 위의 TS 의 table 에서 보듯이 offset + 8 에는 pointer 가 있다. 이 pointer 를 esi 에 넣고 다시 같은 방법으로 callback 함수 호출을 하는 것으로 보아, 아마도 esi+8 에 있는 pointer 도 TS 일 수 있다. 물론 아닐 수도 있다.


High-level perspective

이제 이 함수를 좀 더 추측 해 보자.

callback 의 return 에 대한 logic
  • callback 이 '0' 을 return 하면, offset+8 에 있는 pointer 를 가져와서
    • pointer 가 '0' 이 아니면, callback 호출하는 부분으로 돌아가고,
    • pointer 가 '0' 이면 return '3'
  • callback 이 '1' 을 return 하면, offset+4 에 있는 pointer 를 가져와서
    • pointer 가 '0' 이 아니면, callback 호출하는 부분으로 돌아가고,
    • pointer 가 '0' 이면 return '2'
  • callback 이 '1', '0' 이 아닌 값을 return 하면,
    • return '1'
56DD3175 로 jump 하는 녀석들은 함수가 끝나는 지점인데, 여기서 보면 return value (EAX)는 1, 2, 3 의 3가지가 있다. 이것은 "같다", "작다", "크다" 등의 의미가 될 수 있다.
이 녀석이 linked list 의 구조에서 traverse 를 하는 것이라면, 한 방향으로 가다가 한번은 반대 방향으로 틀어서 값을 찾는 부분이 존재할 것인데, 여기서는 한방향으로 계속 가다가도, 갑자기 다른 방향으로 계속 가기도 하고 한다. 이런 구조는 tree 구조를 traverse 하는 데에 알맞다.
그러면 callback 에서 return 하는 값 '0', '1' 은 '작은 경우', '큰 경우' 로 생각 해 볼 수 있다. 그러면 '0'(작은) 경우에 offset + 8 을 가져오는 것으로 보아, offset + 8 이 left-node 라고 추측할 수 있고, '1' 인 경우에 가져오는 offset + 4 가 right-node 라고 생각 해 볼 수 있다.
이렇게 특정 element 를 찾을 때까지 tree 를 traverse 하는 것은 binary search algorithm 이 있다. 이 assembly 함수가 이 binary search 구조를 닮았다. binary search 의 방법으로 원하는 위치를 찾는 것으로 볼 수 있겠다.

Callback 의 parameters
56DD3156 > 8D46 18 LEA EAX,DWORD PTR DS:[ESI+18]
56DD3159 . 50 PUSH EAX ; 3rd parameter56DD315A . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; 2nd parameter56DD315D . 57 PUSH EDI ; 1st parameter56DD315E . FF57 18 CALL DWORD PTR DS:[EDI+18]
callback 에서 사용하는 parameter 에 대해 알아보자. 위에서 설명했듯이
  1. 첫 번째는 root table data structure(TS) 이고,
  2. 2번 째는 이 함수(우리가 분석중인)로 넘어온 parameter 이고
  3. 3번째는 ESI+18 이다.
먼저 첫 번째 parameter 를 보자. InsertElementGenericTable 이 쓰이는 일반적인 방법을 고민해 보자. 지금의 함수는 이 InsertElementGenericTable 을 완성해 주는 것인데, 우리가 위에서 이 자료구조는 tree 같을 것이라 추측했다. 그러면 분명 어디에선가 root node 를 넘겨줬을 것이다. 그것이 바로 EDI 일 것이다. (우리는 이전 글에서 TS 의 첫 번째 element 가 root 일 것이라 추측했다.) 이것은 이전의 다른 함수들에서도 첫번째 parameter 로 root node 를 넘겨주는 것과 비슷한 경향을 보인다.
그럼 3번째 parameter 를 한 번 보자. 3rd parameter 는 ESI+18이 가리키는 값인데, 우리는 위에서 loop 을 돌면서 ESI 를 바꿔주면서 traverse 를 하는 것을 봤다. 그렇기 때문에 이 [ESI+18] 은 아마도 현재 우리가 traverse 하려고 하는 current node 일 것이다.
이제 2번째 parameter 만 알아내면 되는데, 이것은 상식적으로 유추 해 보자. 이 함수는 insert 에서 호출하고 있으며, binary search 를 사용하고 있다. 그렇다면, 이 2번째 값이 아마도 "insert 하려는 값"일 것이다.
이 내용을 토대로 prototype 을 써본다면 아래와 비슷할 것이다.
int (*stdcall function_name)(TS root_node, void* new_element, void* element_of_current_node)




Reference

  1. RtlInsertElementGenericTable, Chapter 5, Beyond documentation, Reversing: Secrets of Reverse Engineering
  2. Effects of Working-Set Tuning on Reversing, Appendix A, Reversing: Secrets of Reverse Engineering

[컴][Hack][디버그] disassembly code 분석 방법 - 2



RtlNumberGenericTableElements

63D6E010 >   8BFF           MOV EDI,EDI
63D6E012  /. 55             PUSH EBP
63D6E013  |. 8BEC           MOV EBP,ESP
63D6E015  |. 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
63D6E018  |. 8B40 14        MOV EAX,DWORD PTR DS:[EAX+14]
63D6E01B  |. 5D             POP EBP
63D6E01C  \. C2 0400        RETN 4
여기서는 table 의 개수를 알려주는 함수라 짐작하고 분석을 한다. 만약 총개수를 가지고 있는 변수가 있다면, 아마 root node 가 그 변수를 가지고 있을 것이다.

그래서 여기서는 첫번째 parameter 가 root node 일 것이라고 가정해 보는 것이다.

여기를 통해 param1 번째 녀석(ebp+8) 의 offset +14 이 GenericTable 의 element 의 개수 를 가리키는 것을 알았다.

RtlIsGenericTableEmpty

63D6DDAD >   8BFF           MOV EDI,EDI
63D6DDAF  /. 55             PUSH EBP
63D6DDB0  |. 8BEC           MOV EBP,ESP
63D6DDB2  |. 8B4D 08        MOV ECX,DWORD PTR SS:[EBP+8]
63D6DDB5  |. 33C0           XOR EAX,EAX
63D6DDB7  |. 3901           CMP DWORD PTR DS:[ECX],EAX
63D6DDB9  |. 0F94C0         SETE AL
63D6DDBC  |. 5D             POP EBP
63D6DDBD  \. C2 0400        RETN 4
cmp x, y ; x 와 y 가 같은 경우, ZF = 1 로 set 된다.[2]
sete al ; Set byte to '1' if equal (ZF=1)
결국 아래와 같은 code 가 된다.
cmp dword ptr ds:[ecx],eax
sete al
; c- code
if (*ecx == eax)
  set al
결국 param1 이 0 이면 AL 이 '1' 이 된다. 즉, '1'(true) 을 return 해준다.
참고로, AL 은 EAX 의 lower part 를 이야기 한다. EAX 는 return value 를 저장하는 데에도 쓰인다. [3]

여기서 param1 이 '0' 이면 table 이 empty 를 뜻한다는 것을 알았다. 주의할 점은 [ECX]를 가지고 비교한 것이다. 그렇기 때문에 이건 null check 가 아니라 param 1의 member1 가 pointer 일 수도 있다는 뜻일 것이다.


RtlGetElementGenericTable

63D1C124 >   8BFF           MOV EDI,EDI
63D1C126   . 55             PUSH EBP
63D1C127   . 8BEC           MOV EBP,ESP
63D1C129   . 8B4D 08        MOV ECX,DWORD PTR SS:[EBP+8] ; ecx = root of structure A
63D1C12C   . 8B51 14        MOV EDX,DWORD PTR DS:[ECX+14] ; edx = offset +14 from A
63D1C12F   . 8B41 0C        MOV EAX,DWORD PTR DS:[ECX+C] ; eax = offset +C from A
63D1C132   . 53             PUSH EBX
63D1C133   . 56             PUSH ESI
63D1C134   . 8B71 10        MOV ESI,DWORD PTR DS:[ECX+10] ; esi = offset +10 from A
63D1C137   . 57             PUSH EDI
63D1C138   . 8B7D 0C        MOV EDI,DWORD PTR SS:[EBP+C] ; edi = 2nd param
63D1C13B   . 8D5F 01        LEA EBX,DWORD PTR DS:[EDI+1] ; ebx = edi + 1
63D1C13E   . 895D 08        MOV DWORD PTR SS:[EBP+8],EBX ; 1st param = ebx
63D1C141   . 83FF FF        CMP EDI,-1 ; if( edi == -1 )
63D1C144   . 74 35          JE SHORT ntdll_1.63D1C17B
63D1C146   . 3BDA           CMP EBX,EDX ; if ( ebx > member6 )
63D1C148   . 77 31          JA SHORT ntdll_1.63D1C17B ; jump above
63D1C14A   . 3BF3           CMP ESI,EBX ; if( offset_10_from_A == ebx )
63D1C14C   . 74 23          JE SHORT ntdll_1.63D1C171
63D1C14E   . 0F87 542B0800  JA ntdll_1.63D9ECA8
63D1C154   . 8BFB           MOV EDI,EBX ; edi = ebx
63D1C156   . 2BD3           SUB EDX,EBX ; edx - ebx
63D1C158   . 2BFE           SUB EDI,ESI
63D1C15A   . 42             INC EDX
63D1C15B   . 3BFA           CMP EDI,EDX
63D1C15D   . 77 20          JA SHORT ntdll_1.63D1C17F
63D1C15F   . 85FF           TEST EDI,EDI
63D1C161   . 74 05          JE SHORT ntdll_1.63D1C168
63D1C163   > 4F             DEC EDI
63D1C164   . 8B00           MOV EAX,DWORD PTR DS:[EAX]
63D1C166   .^75 FB          JNZ SHORT ntdll_1.63D1C163
63D1C168   > 8B55 08        MOV EDX,DWORD PTR SS:[EBP+8]
63D1C16B   . 8941 0C        MOV DWORD PTR DS:[ECX+C],EAX
63D1C16E   . 8951 10        MOV DWORD PTR DS:[ECX+10],EDX
63D1C171   > 83C0 0C        ADD EAX,0C ;  eax = eax + 0xC
63D1C174   > 5F             POP EDI
63D1C175   . 5E             POP ESI
63D1C176   . 5B             POP EBX
63D1C177   . 5D             POP EBP
63D1C178   . C2 0800        RETN 8
63D1C17B   > 33C0           XOR EAX,EAX
63D1C17D   .^EB F5          JMP SHORT ntdll_1.63D1C174

ecx(= ebp+8)param 1offset + 0member 1pointer
ecx+4offset + 4member 2pointer
offset + 8member 3pointer
offset + cmember 4pointer
offset + 10member 5
offset + 14member 6element 총개수
offset + 18member 7
offset + 1cmember 8
offset + 20member 9
offset + 24member 10


eaxmember 4pointer
esimember 5
edxmember 6element 총개수
edi(=ebp+c)param 2index of element to get
ebxparam 2 +1

우리는 RtlNumberGenericTableElement 에서 root node 가 "첫번째 parameter" 로 넘어오는 것을 확인했다. 보통 api 는 이런 parameter ordering 을 잘 지킨다. 그러므로 여기서 첫번째로 넘어오는 parameter 도 root 라고 가정해 보는 것도 틀린 이야기는 아닐 것이다.

JA (jump if above)를 사용한 것으로 보아 EBX, EDX 가 unsigned 로 사용되었다고 알 수 있다. 보통, signed 로 사용된 경우에는 JG 를 사용한다.

mov edi,dword ptr ss:[ebp+c] ; edi = 2nd param
lea ebx,dword ptr ds:[edi+1] ; ebx = edi + 1
cmp edi,-1 ; if( edi == -1 )
je short ntdll_1.63d1c17b
cmp ebx,edx ; if ( ebx > member6 )
ja short ntdll_1.63d1c17b ; jump above

XOR EAX,EAX ; ntdll_1.63D1C17B

; c-code
if( idx == -1 || idx+1 > elementCount)
  return 0;
위의 두 jump instructions 이 ntdll_1.63d1c17b 로 jump 하는 것으로 보아, 같은 조건 문 안에 묶여 있는 것을 알 수 있다.
63d1c17b XOR EAX,EAX
eax 를 '0' 으로 만들기 때문에 예외(error 또는 exception) 일 가능성이 있다.
member6 은 위에서 우리가 element 의 개수라는 것을 알았다. 그러면 edi, ebx 가 element 의 개수와 비교하는 것으로 봐서 edi 로 들어온 2nd parameter 가 index 일 것이라고 유추할 수 있다.
; c-code
if( idx == -1 || idx+1 > elementCount)
  return 0;
그런데, 여기서 idx+1 부분은 ebx 에 저장되어서 함수내의 여러 instruction 에서 사용되어 진다. 그래서 우리는 이 녀석이 local variable 에 할당되어서 사용되었다고 가정할 수 있다. 또는 여러 개의 idx+1 를 이용한 연산이 존재하는데 그것을 compiler 가 최적화를 시켰을 수도 있다.
; c-code
nextIdx = idx+1
if( idx == -1 || nextIdx > elementCount)
  return 0;
esi 와 ebx 를 비교하는데, ebx 에는 index 와 관련된 값이 들어 있다. 그러므로 esi, 다시 말하면, offset +10 의 값도 index 와 관련된 값이라고 추측해 볼 수 있다.


eaxmember 4pointer
esimember 5index 와 관련된 어떤 값
edxmember 6element 총개수
edi(=ebp+c)param 2index of element to get
ebxparam 2 +1


cmp esi,ebx ; if( offset_10_from_a == ebx )
je short ntdll_1.63D1C171
ja ntdll_1.63d9eca8
mov edi,ebx ; edi = ebx // 이 부분은 if(offset_10_from_a < ebx) 일 때
sub edx,ebx ; edx - ebx

; from 63D1C171
add eax,0c ; eax += 0xC
pop edi
pop esi
pop ebx
pop ebp
retn 8
여기서 return 값을 기존의 eax 값에 12 를 더한 값(offset + C)을 전해준다는 것을 알 수 있다. 우리는 앞에서 GenericTable 의 data structure 의 root 에서 offset+C 가 GenericTable 의 pointer 라는 것을 알고 있다. 그리고 이 pointer 에서 12(0xC) 를 더한 값은 이 pointer 들을 지나 바로 data 에 접근할 수 있게 해 주는 code 인 것이다.


63D1C163   > 4F             DEC EDI
63D1C164   . 8B00           MOV EAX,DWORD PTR DS:[EAX]
63D1C166   .^75 FB          JNZ SHORT ntdll_1.63D1C163


이 부분은 loop 이다.

JNZ 는 ZF 가 not '0' 이면 계속 63D1C163 으로 jump한다. ZF 는 연산결과가 0 이면 set 된다.[ref. 4] 그러므로 위의 loop 은 EDI 가 '0' 이 될 때까지 loop 을 돌게 된다.


References

  1. http://faydoc.tripod.com/cpu/sete.htm
  2. Appendix A, Reversing: Secrets of Reverse Engineering
  3. http://i5on9i.tistory.com/649
  4. http://wiki.peppercode.net/wiki/published/x86+Flags+Register

[컴][Hack][디버그] disassembly code 분석 방법 - 1

리버싱 기초 / 리버스 엔지니어링 시작 방법 / 어디서부터 리버스 엔지니어링을 시작할까 / 함수 분석 /



이 글에서는 같은 data structure 를 사용하는 함수들을 사용해서 data structure 를 유추 해 보는 과정이다.

먼저, data structure 를 initialize 하는 함수를 통해 data structure 를 유추해 보자. 이 곳에 있는 글은 ref.1 의 내용을 조금 각색한 내용이다.

ntdll.dll 에 있는 RtlInitializeGenericTable 의 disassembly code 를 통해 GenericTable 이 어떤 구조인지를 유추 해 보는 글이다.

dll 에서 API 를 찾고, 이 dll 을 사용하는 binary 를 찾는다. 이를 통해 어떤 동작을 하는 지 짐작할 수 있고, 어떻게 이 함수를 사용하는 지 알 수 있다.

RtlInitializeGenericTable

Immunity Debugger 나 Olly Debugger 를 이용해서 ntdll.dll 에서 RtlInitializeGenericTable 을 찾아가보면, 아래와 같은 코드가 보인다. 아래 코드는 Immunity Debugger 를 사용해서 가져온 내용이다.
770D6698 > 8BFF             MOV EDI,EDI
770D669A   55               PUSH EBP
770D669B   8BEC             MOV EBP,ESP
770D669D   8B45 08          MOV EAX,DWORD PTR SS:[EBP+8]
770D66A0   33D2             XOR EDX,EDX
770D66A2   8D48 04          LEA ECX,DWORD PTR DS:[EAX+4]
770D66A5   8910             MOV DWORD PTR DS:[EAX],EDX
770D66A7   8949 04          MOV DWORD PTR DS:[ECX+4],ECX
770D66AA   8909             MOV DWORD PTR DS:[ECX],ECX
770D66AC   8948 0C          MOV DWORD PTR DS:[EAX+C],ECX
770D66AF   8B4D 0C          MOV ECX,DWORD PTR SS:[EBP+C]
770D66B2   8948 18          MOV DWORD PTR DS:[EAX+18],ECX
770D66B5   8B4D 10          MOV ECX,DWORD PTR SS:[EBP+10]
770D66B8   8948 1C          MOV DWORD PTR DS:[EAX+1C],ECX            ; generict.004110C8
770D66BB   8B4D 14          MOV ECX,DWORD PTR SS:[EBP+14]
770D66BE   8948 20          MOV DWORD PTR DS:[EAX+20],ECX
770D66C1   8B4D 18          MOV ECX,DWORD PTR SS:[EBP+18]
770D66C4   8950 14          MOV DWORD PTR DS:[EAX+14],EDX
770D66C7   8950 10          MOV DWORD PTR DS:[EAX+10],EDX
770D66CA   8948 24          MOV DWORD PTR DS:[EAX+24],ECX
770D66CD   5D               POP EBP
770D66CE   C2 1400          RETN 14
함수 호출 부분에는 아래 처럼 ebp 를 새롭게 setting 하는 부분이 들어 있다. 그러니 그냥 무시해도 된다. 참고로, parameter(그림에서는 arg) 를 stack 에 넣는 부분(instructions)은 함수를 call 하기 전에 이루어진다.
push ebp
mov ebp, esp

stack_Frame


Calling Convention 유추

함수의 함수호출규약(calling convention) 을 찾아보자. 그러기 위해서는 일단 RET 를 확인하자.
RET 14
14 는 stack 에서 20(0x14) 바이트를 unwind 해야 된다고 알려준다. 32 bit 컴퓨터이기 때문에, parameter 들이 4 byte 에 맞춰서 만들어졌을 테니, 20 byte 는 5개의 parameter 라고 알려준다.

만약 parameter 하나가 4 byte 보다 큰 경우에는 parameter 의 개수가 5개보다 적을 수 있다. 그러나, parameter 들이 32-bit 로 aligned 되어 있기에, 5 개보다 많을 수는 없다. [1]

function(callee, 호출이 된 함수) 이 unwind 를 하는 것은 cdecl 함수가 아니다. cdecl calling convention 은 caller(호출하는 함수) 가 stack 을 unwind 하게 되어 있다.(참고: http://i5on9i.egloos.com/4841016 )

caller 로 부터 어떤 register 도 가져오지 않았다. _fastcall calling convention 은 parameter들 중 처음 2개 까지만 레지스터(ecx, edx)에 저장하고, 나머지는 스택에 push 한다.[2] 스택 프레임 반환 작업(unwind)은 callee 가 한다. 그러므로 _fastcall 도 아니다.

그로므로 stdcall 이라고 유추할 수 있다.(물론 다른 convention 도 있지만, 많이 쓰이는 것 중에서 유추한 듯 하다.)



자료구조 분석

분석 Step 1.

이제 그 다음 line 을 보자.
mov eax,dword ptr ss:[ebp+8]
xor  edx,edx
lea  ecx,dword ptr ds:[eax+4]
ss 는 여기서는 무시해도 된다. ss 가 궁금하다면, 아래 글을 참고 하자.
ss 관한 설명 : How are the segment registers (fs, gs, cs, ss, ds, es) used in x86 and amd64?

그럼 이제, 한 줄 씩 살펴보자.
mov eax, dword ptr ss:[ebp+8]   // ebp+8 에 있는 녀석을 eax 로 옮긴다.
  • ebp+4 에는 return address 가 있으며,
  • ebp+8 에는 1번 째 parameter 가 들어있다.
여하튼 ebp+8 에 있는 녀석(첫번째 parameter)을 eax 로 옮기는 instruction 이다.
xor edx, edx     ; '0' 으로 초기화 '0' 으로 만들 때는 보통 xor 이 쓰인다. mov edx, 0 보다 machine code 가 짧기 때문이라고 한다.[1]
lea ecx, dword ptr ds:[eax+4]
load effective address는 주로 address 를 계산하는데 쓰인다고 한다. [] 가 있지만, lea 는 실제로 메모리에 접근하지 않는다. 여기서는
ecx = eax + 4     ; eax 가 "첫 번째 element를 가리키는 주소" 이니 eax+4 는 "두 번째 element의 주소" 이다.
로 봐도 무방하다.

간단히 c-code 형식으로 나타내면 아래와 같다.
eax = param1
ecx = param2

분석 Step 2.

이제 그 다음 line 들도 분석 해 보자.
mov dword ptr ds:[eax], edx      ; [eax] 를 '0'(edx)으로 초기화 
mov dword ptr ds:[ecx+4], ecx   ; structure 의 3번째 member 에 2번째 member의 address 를 넣는다.
mov dword ptr ds:[ecx], ecx      ; 2번째 member의 address 를 [ecx] 에 넣는다.
mov dword ptr ds:[ecx+c], ecx   ; c 는 0xC, 12 이다. 4번째 member의 address 를 [ecx] 에 넣는다.
c 코드로 나타내면, 아래 같은 모양이다.
SomeStruct->m1 = 0;
SomeStruct->m2 = &SomeStruct->m2;
SomeStruct->m3 = &SomeStruct->m2;
SomeStruct->m4 = &SomeStruct->m2;

분석 Step 3.

mov ecx, dword ptr ss:[ebp+c]
mov dword ptr ds:[eax+18], ecx  ; 0x18 는 24
mov ecx, dword ptr ss:[ebp+10]
mov dword ptr ds:[eax+1c], ecx
; c code
SomeStruct->m7 = param2;
SomeStruct->m8 = param3;

mov ecx, dword ptr ss:[ebp+14]
mov dword ptr ds:[eax+20], ecx
mov ecx. dword ptr ss:[ebp+18], ecx
mov dword ptr ds:[eax+14], edx
mov dword ptr ds:[eax+10], edx
mov dword ptr ds:[eax+24], ecx
; c code
SomeStruct->m9 = param4;
SomeStruct->m6 = 0;
SomeStruct->m7 = 0;
SomeStruct->m10 = param5;

정리

이 함수disassembly code 의 [eax+24] 를 통해 이 GenericTable structure 의 size 가 40-byte 정도 된다는 것을 알 수 있고, 만약 structure 의 member 한 개가 4-byte 라고 가정하면, 약 10개의 member 를 가지고 있다고 유추할 수 있다. 이것을 c-code 로 나타내면 아래와 같을 것이다.
struct TABLE
{
  UNKNOWN       m1;
  UNKNOWN_PTR m2;
  UNKNOWN_PTR m3;
  UNKNOWN_PTR m4;
  UNKNOWN       m5;
  UNKNOWN       m6;
  UNKNOWN       m7;
  UNKNOWN       m8;
  UNKNOWN       m9;
  UNKNOWN       m10;
};


References

  1. p. 146, Beyond Documentation, Reversing: Secrets of Reverse Engineering, 2005
  2. http://data-forge.blogspot.kr/2012/01/2-cdecl-stdcall.html

[컴][디버그] Immunity Debugger 이뮤니티 디버거 사용법 - ESP, EBP


immunity debugger 의 오른쪽 아래 창이 stack 화면인데, 여기서 
  • ESP
  • EBP

주소를 확인할 수 있다. 아래 방법을 통해서 ESP, EBP 에 대한 상대주소를 얻을 수 있다.

  • 마우스 오른쪽 버튼 >> address >> relative to ESP or relative to EBP





[컴][윈도우즈] DumpBin

덤프빈 다운로드 /

DumpBin execution version
DumpBin.zip download

사용법

아래처럼 옵션 다음에 실행파일의 path 를 적어주면 된다.
dumpbin /option exe_path
c:\>dumpbin /disasem c:\windows\notepad.exe

자세한 설명은 아래를 참고하자.

/EXPORTS

c:\>dumpbin /exports c:\windows\system32/ntdll.dll

이렇게 하면, export 하고 있는 함수의 리스트를 볼 수 있다.

Referenece

  1. http://originaldll.com/
  2. http://www.nodevice.com/dll/MSDIS110_DLL/item10670.html

[컴][윈도우즈] Dependency walker

의존성 검사 / 실행파일에 필요한 dll 찾는 방법 / 설치할 때 필요한 dll 찾는 방법 /


dependency walker 는 의존성(dependency) 를 check 해 준다.
  • exe 같은 것을 copy 해서 옮겨갈 때 어떤 파일들이 필요한지를 알고 싶은 경우(modul initialization failures)[2]
  • circular dependency 등의 error 를 찾아 낼 때.[1]
모든 종류의 dependency 를 다 다룰 수 있다고 한다.
Dependency Walker handles all types of module dependencies, including implicit, explicit (dynamic / runtime), forwarded, delay-loaded, and injected.[1]

Download

Dependency walker Download 는 아래 경로에서 할 수 있다.
http://www.dependencywalker.com/

사용법

사용법은 ref. 2, 또는 ref. 3 을 참고 하자.


Reference

  1. http://www.dependencywalker.com/
  2. Dependency Walker는 무엇에 쓰는 물건일까?, 마이크로소프트웨어
  3. 알아두면 편리한 DLL viewer –Dependency Walker, 2009년. 3월, 네이버 블로그

[컴][윈도우즈] windows용 debugger

무료 디버거 / 올리 디버거 / 윈디버거 / 닷넷 디버거 / 닷넷 디스어셈블러 /


User mode debugger

.EXE disassembler

WinDbg

WinMain 이 시작하기 전에 static linked DLL 들을 초기화하는데, 이 부분에서부터 디버깅(step through)을 할 수 있다.[1]
Powerful extension 에서 많은 정보를 얻을 수 있다.[1]
Powerful extension 로 얻을 수 있는 정보[1]
  • active user-mode heap 들을 dump
  • security tokens
  • PEM(Process Environment Block)
  • TEB(Thread Environment Block)
  • system loader 의 current state

Olly debugger

WinDbg 를 사용해야만 하는 경우[1]
  • OS 에 많이 연관되어있는(heavily integrated) 녀석
  • extension 에서 제공하는 정보가 필요한 경우
  • DLL 초기화 부분을 봐야 하는 경우

위의 경우 이외에는 WinDbg 보다는 Olly debugger 가 낫다.[1]
WinDbg 대비 Olly debugger 의 장점[1]
  • UI
  • better disassembler
  • code 분석 능력

.NET disassembler

PEBrowse Professional Interactive
http://www.smidgeonsoft.prohosting.com/


Kernel mode Debugger

kernel mode code 를 reversing 할 때 kernel mode debugger 는 필수다. 하지만 setup 이 힘들고, OS 를 불안정하게 만든다. 그리고 전체 시스템을 suspend 시킨다. 그래서 꼭 필요한 경우가 아니라면 user-mode debugger 가 낫다.[1]
  • WinDbg
  • Numega SoftICE


Reference

  1. User-Mode Debugger , Chater 4. Reversion : Secrets Of reversing engineering, Eldad Eilam, 2005년

[컴][C#] .NET Assembly decompiler

.NET Assembly 를 decompile 하는 법 / c# decompile 하는 법 / 디컴파일러 / 디컴파일 하는 방법 / c# reverse engineering / 닷넷 어셈블리 디컴파일러

 

.NET Assembly 로 되어 있는 .exe 파일에서 MSIL을 가져오는 tool 이 ildasm 이다. 이 녀석은 .NET framework SDK 에 들어있다.

 

ildasm

ildasm 위치

Visual C# .NET 2010 을 설치했다면 일반적으로 아래 경로에 있다.

c:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\ildasm.exe

사용법

ildasm exe_path

더욱 자세한 사용법은 ref. 1를 참고하자.

 

Reflector

그리고 여기서 다시 MSIL 을 C# source code 로 변환시킬 때 reflector 라고 불리는 tool을 사용한다. 이 부분에 대한 사항은 ref. 1 을 참고하자.

 

See Also

  1. IL assembler 관련 책 목록, amazon

 

Reference

  1. Decompiling .NET Assemblies, 2004년 8월
  2. Ildasm.exe (MSIL Disassembler), MSDN

[컴][파이썬] CPython 과 Cython


CPython 이랑 Cython 은 이름이 비슷하게 생겨서 나는 같은 것 인줄 알았다.^^;;;;
그런데, 찾아보니 CPython 은 우리가 기본적으로 쓰는 python 의 interpreter 를 얘기하는 것이었고, Cython 은 내가 알고 있던, python 에 추가적으로 static type 등을 정의할 수 있게 해주는 또 하나의 language 였다.
  • CPython : interpreter
  • Cython : programming language

아래는 wiki 의 내용을 단순히 요약한 내용이다. 자세한 사항은 ref. 1, ref. 2 를 참고하자.

CPython

C로 작성된 python programming language 의 구현(implementation)이다.

우리가 기본적으로 쓰고 있는 것 python 의 interpreter 가 이 CPython 이다.

CPython 은 bytecode interpreter 이다.
C 같은 외부 함수에 접근할 수 있는 interface(foreign function interface)를 갖고 있다. 이 interface 를 통해서 bindings 을 작성할 수 있다.


Cython

Cython 은 python 의 superset(python + 추가요소)
Cython 은 CPython extension module 을 만들어준다.

추가요소
  • c/c++ 를 호출하는 함수 interface 와
  • static type 의 정의
    • routine parameter
    • 지역 변수들(local variables)
    • 함수의 결과들(subroutine results)
    • class 의 attributes

확장자

.pyx 확장자(extension)을 갖는다.

data type

python 의 primitive type 을 쓸 수도 있고, c types 를 정의할 수도 있다.

CPython 과 실행방법의 차이

똑같은 python code 여도 좀 더 적은 computing resource (core memory, processing cycles)를 사용한다. 왜냐하면, CPython 과 Cython 의 실행모델(exectuion model)차이 때문이다.

일반적은 python code 를 실행하면, CPython의 VM 에 의해 load 되고, 실행되면, runtime 과 program 모두가 computing resource 를 사용한다.

Cython 은 C code 로 컴파일되고, 이게 또 기계어(compiled code) 로 compile 된다. 그래서 VM 은 program 이 load 될 때만 잠깐 사용된다.

C 가 결국 intermediate language 가 되고, 결국 performance 는 c compiler 에 의해 좌우된다.

Cython 은 그래서 numerical computing 에 사용되기도 하며,
많은 c/c++의 library 들이 Pythonic binding 을 제공하는 경우에도 많이 쓰인다.


Reference

  1. http://en.wikipedia.org/wiki/Cython

[컴][디버그] windows 에서 guard page 설정하기 - memory breakpoint

memory breakpoint using page fault on windwos

 

아직 부정확한 부분이 있어서, 정리차원으로 적어놓는다. PyDbg 부분에 대한 분석 이후에 update 를 해야 할 듯 하다.

 

Procedure

  1. page size 를 알아내고,
  2. page 에 permission 을 설정해서 guard page 처럼 작동하도록 한다.
  3. GUARD_PAGE_EXCEPTION 이 발생한다.
  4. exception handler 에서 다시 page 의 permission 을 돌려놓고(이 부분은 OS가 해준다.[ref. 1]), execution 을 계속 이어나간다.

 

 

Page Size

우리가 다룰 page 의 정확한 사이즈를 구하기 위해서, Operating System(OS) 에 default page size 를 물어봐야 한다. GetSystemInfo() 로 할 수 있다. 이 함수에서 SYSTEM_INFO structure 를 채워주는데 이 structure 가 dwPageSize 를 가지고 있다. 이 값이 default page size 가 된다.

 

Permission

page 정보

page permission 을 조정해 보자. 그러기 위해서 먼저 우리가 breakpoint 를 걸고 싶은 주소에 해당하는 page 의 정보를 가져오자. VirtualQueryEx() 로 가능하다. 이 함수에서 MEMORY_BASIC_INFORMATION structure 에 값이 채워지는데, 이 structure 가 가지고 있는 정보가 memory page 에 대한 정보를 가지고 있다.

 

permission 설정

여기에 있는 BaseAddress 정보가 시작점이 된다. permission 을 설정하는 함수는 VirtualProtectEx() 인데, 여기 2번째 인자로 들어가는 주소로 BaseAddress 를 넣어주면 된다.


guar page 에 access 를 해서 exception 이 발생하면 OS 가 메모리에 있는 그 page 의 exception 을 알아서 제거해 준다. 그래서 굳이 permission 을 제거하는 루틴을 짜지 않아도 괜찮다.

 

 

Demo

 

# source from Gray Hat Python
# edited by namh



memory_breakpoints = {}

creation_flags = DEBUG_PROCESS

# instantiate the structs
startupinfo = STARTUPINFO()
process_information = PROCESS_INFORMATION()

startupinfo.dwFlags = 0x1
startupinfo.wShowWindow = 0x0
startupinfo.cb = sizeof(startupinfo)

kernel32.CreateProcessA(path_to_exe,
None,
None,
None,
None,
creation_flags,
None,
None,
byref(startupinfo),
byref(process_information)):

pid = process_information.dwProcessId
h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,pid)

system_info = SYSTEM_INFO()
kernel32.GetSystemInfo(byref(system_info))

page_size = system_info.dwPageSize


mbi = MEMORY_BASIC_INFORMATION()


# Attempt to discover the base address of the memory page
if kernel32.VirtualQueryEx(\
h_process, address, byref(mbi), sizeof(mbi)) < sizeof(mbi):
return False


current_page = mbi.BaseAddress

# We will set the permissions on all pages that are
# affected by our memory breakpoint.
while current_page <= address + size:

# Add the page to the list, this will
# differentiate our guarded pages from those
# that were set by the OS or the debuggee process
guarded_pages.append(current_page)

old_protection = c_ulong(0)
if not kernel32.VirtualProtectEx(\
h_process, current_page, size,\
mbi.Protect | PAGE_GUARD, byref(old_protection)):
return False

# Increase our range by the size of the
# default system memory page size
current_page += self.page_size

# Add the memory breakpoint to our global list
memory_breakpoints[address] = (address, size, mbi)

return True

 


References



  1. Chapter 3, Gray Hat Python
  2. http://www.codeproject.com/Articles/186230/Extending-windbg-with-Page-Fault-Breakpoints