>

def patch(code):
	for i in range(len(code)):
		PatchByte(ScreenEA()+i,ord(code[i]))

PatchByte(ea, 바꿀바이트) => ea 주소의 바이트를 바꿔줌

ScreenEA() => 현재 커서로 찍은(노란색 빛이 나는) ea의 주소 리턴



def extract_file(ea,size,filename):
	f = open(filename,"wb")
	data = ""
	for i in range(ea,ea+size):
		data += chr(Byte(i))
	f.write(data)
	f.close()


주소, 사이즈, 파일이름 넣으면 그 사이즈만큼 추출

'Memo' 카테고리의 다른 글

함수 프롤로그, 에필로그  (0) 2015.10.16
x86 어셈블리어 분기  (0) 2015.10.02
[Bash script] Internal Variables  (0) 2015.09.08
IDA Hexray 깨부수기  (0) 2015.09.03
Windows Message List  (0) 2015.08.31
Posted by Mungsul
,

작년,재작년 때 나가서 각각 콩등 한 Layer7 CTF. 

문제 스타일과 퀄리티가 나랑 맞아서 요번에도 일반인으로 참가했다.

가족행사에 참가해서 많이 하지 못했기 때문에 대회 때 풀다가 넘긴 것들을 풀이하겠다.


Reverse Me

MP3 파일을 하나 제공해주는데, hex 에디터로 맨 끄트머리를 확인해보면 exe 파일이 거꾸로 삽입되어 있다는 것을 확인할 수 있다.

거꾸로 돌려주고 IDA로 살펴보면 8바이트를 입력받아 요러쿵 저러쿵 연산하는 것을 볼 수 있다.

한바이트를 2비트씩 나눠서 두 비트를 조작하는 연산이고 후에 조작하지 않은 4바이트 입력 데이터와 XOR 한다.

처음 접근은 Decoder 만들기였으나, Decoder 만드는 과정에서 연산 후 데이터를 같은 함수에 넣으면 연산 전 데이터가 나온다는 사실을 알게되었다.

그러므로, 입력 값을 맨 끝 비교하는 값으로 바꿔주고 실행시키면 단번에 Flag를 얻을 수 있다.




이렇게 바꾸고 돌리면



이렇게 EAX 와 EBX에 원래 값이 예쁘게 들어가 있는 것을 볼 수 있다.

Flag : regedit@


Easy Reversing

Windows 프로그램이다. 분석해보면, WM_CHAR 이벤트를 이용해 키보드로 데이터를 입력받고 입력받은 데이터 체크 루틴이 있다는 것을 확인할 수 있다.



위 사진이 그 루틴인데, 살짝 괴랄하다. result 변수가 6까지 돌기 때문에 맨 마지막 바이트를 0x52 즉 R이라고 유추할 수는 있다. 

0x52 ^ 0xfb 를 하면 v3는 알아낼 수 있지만 이 v3가 ROL(이전 바이트, 이전바이트 & 7) 한 값이기 때문에 ROR을 1에서 7까지 돌린다 해도 해당 바이트가 실제 이전 바이트인지, 연산을 더 진행할 수 있는지에 대한 불확실성이 너무 크다. 그래서 처음 루틴부터 따라가기로 했다.


def ROL(data, shift, size=32):

    shift %= size

    remains = data >> (size - shift)

    body = (data << shift) - (remains << size )

    return (body + remains)

     

 

def ROR(data, shift, size=32):

    shift %= size

    body = data >> shift

    remains = (data << (size - shift)) - (body << size)

    return (body + remains)


xorkey = [0x0a,0xe9,0xda,0xca,0xd,0xe7,0xfb,0x52]


db = {}

db2 = {}

db3 = {}

db4 = {}

db5 = {}

db6 = {}

db7 = {}

db8 = {}


for j in range(0x20,0x7f):

    bit = j & 7

    r = ROL(j,bit,8)

    x = r ^ xorkey[0]

    if x >= 0x20 and x < 0x7f:

        db[chr(j)] = chr(x)

        

for i in db:

    bit = ord(db[i]) & 7

    r = ROL(ord(db[i]),bit,8)

    x = r ^ xorkey[1]

    if x>= 0x20 and x < 0x7f:

        db2[db[i]] = chr(x)


for i in db2:

    bit = ord(db2[i]) & 7

    r = ROL(ord(db2[i]),bit,8)

    x = r ^ xorkey[2]

    if x>= 0x20 and x < 0x7f:

        db3[db2[i]] = chr(x)


for i in db3:

    bit = ord(db3[i]) & 7

    r = ROL(ord(db3[i]),bit,8)

    x = r ^ xorkey[3]

    if x>= 0x20 and x < 0x7f:

        db4[db3[i]] = chr(x)


for i in db4:

    bit = ord(db4[i]) & 7

    r = ROL(ord(db4[i]),bit,8)

    x = r ^ xorkey[4]

    if x>= 0x20 and x < 0x7f:

        db5[db4[i]] = chr(x)


for i in db5:

    bit = ord(db5[i]) & 7

    r = ROL(ord(db5[i]),bit,8)

    x = r ^ xorkey[5]

    if x>= 0x20 and x < 0x7f:

        db6[db5[i]] = chr(x)


for i in db6:

    bit = ord(db6[i]) & 7

    r = ROL(ord(db6[i]),bit,8)

    x = r ^ xorkey[6]

    if x>= 0x20 and x < 0x7f:

        db7[db6[i]] = chr(x)


print db

print db2

print db3

print db4

print db5

print db6

print db7


약간 비효율적이지만 이렇게 트레이싱해서 마지막 바이트가 0x52 인 것을 찾고 따라가면 String을 알아맞출 수 있다.


{'!': 'H', ' ': '*', '$': 'H', ')': 'X', '(': '"', '+': 'S', '1': 'h', '0': ':', '4': 'I', '9': 'x', '8': '2', '@': 'J', 'D': 'N', 'H': 'B', 'K': 'P', 'J': '#', 'P': 'Z', 'R': 'C', 'T': 'O', 'X': 'R', 'Z': 'c', '`': 'j', 'd': 'L', 'h': 'b', 'k': 'Q', 'p': 'z', 't': 'M', 'x': 'r'}

{'r': ' ', '"': 'a', 'I': '{', '*': 'A', 'M': '@', 'L': '-', 'O': 'N', 'N': 'z', 'Q': 'K', 'S': 's', '2': '!', 'j': '@', 'b': '`'}

{'A': 'X', 's': 'A', 'z': '3', 'N': 'I'}

{'A': 'H', 'I': 'X', '3': 'S'}

{'H': 'E', 'X': 'U'}

{'U': 'M', 'E': 'O'}

{'M': 'R', 'O': '\\'}


마지막 바이트가 R 인 것을 따라가면 => TONIXUMR 라는 값을 얻을 수 있다.

문자열 체크 루틴은 WM_DESTROY 일때 분기하므로 TONIXUMB 문자열을 입력하고 창을 닫으면 루틴이 통과되는 것을 확인할 수 있다.

하지만 Fail 이라는 Message Box가 띄워지는데, 그 이유는 다음 루틴 때문이다.


문자열 체크 루틴을 지나면 본격적으로 Flag 체크 루틴에 돌입하는데, 최종적으로 v9가 XOR 한 값과 같아야 한다. XOR한 값은 사용자 입력이 아니므로 v9를 살펴봐야 한다.

처음, 자기자신을 읽어 맨 끝 12바이트만 제외하고 모두 XOR 하는데 이용한다. 나머지 12바이트는 4바이트씩 잘라 또 XOR 하는데 사용된다. 그리고 8~12 바이트를 받는 과정에서 문제가 있음을 짐작할 수 있다.

hex 에디터로 해당 파일을 열어서 맨 끝 4바이트를 보면 0으로 채워져있는 것이 보인다. 이 값을 비교하는 XOR 값으로 채워넣거나 강제로 체크 루틴을 우회하면 Flag를 얻을 수 있다.

Flag : notepad!


------

누군가에겐 아주 쉬운 문제였을지는 몰라도 나에게는 오랜만의 여흥이자 머리를 말랑말랑하게 만드는 좋은 원동력이 된 것 같다. 

문제를 만든 출제자에게 감사를 보내며 앞으로도 좋은 Layer7 대회가 되길.

'CTF' 카테고리의 다른 글

[HackIM] sandman  (0) 2016.03.03
[hitcon2015] blinkroot  (0) 2015.10.20
Codegate 2015 bookstore  (0) 2015.03.17
christmas CTF Rudolph  (0) 2015.02.20
Codegate 2014 minibomb write-up  (5) 2014.03.09
Posted by Mungsul
,

Windows Message List

Memo 2015. 8. 31. 13:53
WM_NULL = 0x00
WM_CREATE = 0x01
WM_DESTROY = 0x02
WM_MOVE = 0x03
WM_SIZE = 0x05
WM_ACTIVATE = 0x06
WM_SETFOCUS = 0x07
WM_KILLFOCUS = 0x08
WM_ENABLE = 0x0A
WM_SETREDRAW = 0x0B
WM_SETTEXT = 0x0C
WM_GETTEXT = 0x0D
WM_GETTEXTLENGTH = 0x0E
WM_PAINT = 0x0F
WM_CLOSE = 0x10
WM_QUERYENDSESSION = 0x11
WM_QUIT = 0x12
WM_QUERYOPEN = 0x13
WM_ERASEBKGND = 0x14
WM_SYSCOLORCHANGE = 0x15
WM_ENDSESSION = 0x16
WM_SYSTEMERROR = 0x17
WM_SHOWWINDOW = 0x18
WM_CTLCOLOR = 0x19
WM_WININICHANGE = 0x1A
WM_SETTINGCHANGE = 0x1A
WM_DEVMODECHANGE = 0x1B
WM_ACTIVATEAPP = 0x1C
WM_FONTCHANGE = 0x1D
WM_TIMECHANGE = 0x1E
WM_CANCELMODE = 0x1F
WM_SETCURSOR = 0x20
WM_MOUSEACTIVATE = 0x21
WM_CHILDACTIVATE = 0x22
WM_QUEUESYNC = 0x23
WM_GETMINMAXINFO = 0x24
WM_PAINTICON = 0x26
WM_ICONERASEBKGND = 0x27
WM_NEXTDLGCTL = 0x28
WM_SPOOLERSTATUS = 0x2A
WM_DRAWITEM = 0x2B
WM_MEASUREITEM = 0x2C
WM_DELETEITEM = 0x2D
WM_VKEYTOITEM = 0x2E
WM_CHARTOITEM = 0x2F

WM_SETFONT = 0x30
WM_GETFONT = 0x31
WM_SETHOTKEY = 0x32
WM_GETHOTKEY = 0x33
WM_QUERYDRAGICON = 0x37
WM_COMPAREITEM = 0x39
WM_COMPACTING = 0x41
WM_WINDOWPOSCHANGING = 0x46
WM_WINDOWPOSCHANGED = 0x47
WM_POWER = 0x48
WM_COPYDATA = 0x4A
WM_CANCELJOURNAL = 0x4B
WM_NOTIFY = 0x4E
WM_INPUTLANGCHANGEREQUEST = 0x50
WM_INPUTLANGCHANGE = 0x51
WM_TCARD = 0x52
WM_HELP = 0x53
WM_USERCHANGED = 0x54
WM_NOTIFYFORMAT = 0x55
WM_CONTEXTMENU = 0x7B
WM_STYLECHANGING = 0x7C
WM_STYLECHANGED = 0x7D
WM_DISPLAYCHANGE = 0x7E
WM_GETICON = 0x7F
WM_SETICON = 0x80

WM_NCCREATE = 0x81
WM_NCDESTROY = 0x82
WM_NCCALCSIZE = 0x83
WM_NCHITTEST = 0x84
WM_NCPAINT = 0x85
WM_NCACTIVATE = 0x86
WM_GETDLGCODE = 0x87
WM_NCMOUSEMOVE = 0xA0
WM_NCLBUTTONDOWN = 0xA1
WM_NCLBUTTONUP = 0xA2
WM_NCLBUTTONDBLCLK = 0xA3
WM_NCRBUTTONDOWN = 0xA4
WM_NCRBUTTONUP = 0xA5
WM_NCRBUTTONDBLCLK = 0xA6
WM_NCMBUTTONDOWN = 0xA7
WM_NCMBUTTONUP = 0xA8
WM_NCMBUTTONDBLCLK = 0xA9

WM_KEYFIRST = 0x100
WM_KEYDOWN = 0x100
WM_KEYUP = 0x101
WM_CHAR = 0x102
WM_DEADCHAR = 0x103
WM_SYSKEYDOWN = 0x104
WM_SYSKEYUP = 0x105
WM_SYSCHAR = 0x106
WM_SYSDEADCHAR = 0x107
WM_KEYLAST = 0x108

WM_IME_STARTCOMPOSITION = 0x10D
WM_IME_ENDCOMPOSITION = 0x10E
WM_IME_COMPOSITION = 0x10F
WM_IME_KEYLAST = 0x10F

WM_INITDIALOG = 0x110
WM_COMMAND = 0x111
WM_SYSCOMMAND = 0x112
WM_TIMER = 0x113
WM_HSCROLL = 0x114
WM_VSCROLL = 0x115
WM_INITMENU = 0x116
WM_INITMENUPOPUP = 0x117
WM_MENUSELECT = 0x11F
WM_MENUCHAR = 0x120
WM_ENTERIDLE = 0x121

WM_CTLCOLORMSGBOX = 0x132
WM_CTLCOLOREDIT = 0x133
WM_CTLCOLORLISTBOX = 0x134
WM_CTLCOLORBTN = 0x135
WM_CTLCOLORDLG = 0x136
WM_CTLCOLORSCROLLBAR = 0x137
WM_CTLCOLORSTATIC = 0x138

WM_MOUSEFIRST = 0x200
WM_MOUSEMOVE = 0x200
WM_LBUTTONDOWN = 0x201
WM_LBUTTONUP = 0x202
WM_LBUTTONDBLCLK = 0x203
WM_RBUTTONDOWN = 0x204
WM_RBUTTONUP = 0x205
WM_RBUTTONDBLCLK = 0x206
WM_MBUTTONDOWN = 0x207
WM_MBUTTONUP = 0x208
WM_MBUTTONDBLCLK = 0x209
WM_MOUSEWHEEL = 0x20A
WM_MOUSEHWHEEL = 0x20E

WM_PARENTNOTIFY = 0x210
WM_ENTERMENULOOP = 0x211
WM_EXITMENULOOP = 0x212
WM_NEXTMENU = 0x213
WM_SIZING = 0x214
WM_CAPTURECHANGED = 0x215
WM_MOVING = 0x216
WM_POWERBROADCAST = 0x218
WM_DEVICECHANGE = 0x219

WM_MDICREATE = 0x220
WM_MDIDESTROY = 0x221
WM_MDIACTIVATE = 0x222
WM_MDIRESTORE = 0x223
WM_MDINEXT = 0x224
WM_MDIMAXIMIZE = 0x225
WM_MDITILE = 0x226
WM_MDICASCADE = 0x227
WM_MDIICONARRANGE = 0x228
WM_MDIGETACTIVE = 0x229
WM_MDISETMENU = 0x230
WM_ENTERSIZEMOVE = 0x231
WM_EXITSIZEMOVE = 0x232
WM_DROPFILES = 0x233
WM_MDIREFRESHMENU = 0x234

WM_IME_SETCONTEXT = 0x281
WM_IME_NOTIFY = 0x282
WM_IME_CONTROL = 0x283
WM_IME_COMPOSITIONFULL = 0x284
WM_IME_SELECT = 0x285
WM_IME_CHAR = 0x286
WM_IME_KEYDOWN = 0x290
WM_IME_KEYUP = 0x291

WM_MOUSEHOVER = 0x2A1
WM_NCMOUSELEAVE = 0x2A2
WM_MOUSELEAVE = 0x2A3

WM_CUT = 0x300
WM_COPY = 0x301
WM_PASTE = 0x302
WM_CLEAR = 0x303
WM_UNDO = 0x304

WM_RENDERFORMAT = 0x305
WM_RENDERALLFORMATS = 0x306
WM_DESTROYCLIPBOARD = 0x307
WM_DRAWCLIPBOARD = 0x308
WM_PAINTCLIPBOARD = 0x309
WM_VSCROLLCLIPBOARD = 0x30A
WM_SIZECLIPBOARD = 0x30B
WM_ASKCBFORMATNAME = 0x30C
WM_CHANGECBCHAIN = 0x30D
WM_HSCROLLCLIPBOARD = 0x30E
WM_QUERYNEWPALETTE = 0x30F
WM_PALETTEISCHANGING = 0x310
WM_PALETTECHANGED = 0x311

WM_HOTKEY = 0x312
WM_PRINT = 0x317
WM_PRINTCLIENT = 0x318

WM_HANDHELDFIRST = 0x358
WM_HANDHELDLAST = 0x35F
WM_PENWINFIRST = 0x380
WM_PENWINLAST = 0x38F
WM_COALESCE_FIRST = 0x390
WM_COALESCE_LAST = 0x39F
WM_DDE_FIRST = 0x3E0
WM_DDE_INITIATE = 0x3E0
WM_DDE_TERMINATE = 0x3E1
WM_DDE_ADVISE = 0x3E2
WM_DDE_UNADVISE = 0x3E3
WM_DDE_ACK = 0x3E4
WM_DDE_DATA = 0x3E5
WM_DDE_REQUEST = 0x3E6
WM_DDE_POKE = 0x3E7
WM_DDE_EXECUTE = 0x3E8
WM_DDE_LAST = 0x3E8

WM_USER = 0x400
WM_APP = 0x8000

출처 : http://wiki.winehq.org/List_Of_Windows_Messages

'Memo' 카테고리의 다른 글

함수 프롤로그, 에필로그  (0) 2015.10.16
x86 어셈블리어 분기  (0) 2015.10.02
[Bash script] Internal Variables  (0) 2015.09.08
IDA Hexray 깨부수기  (0) 2015.09.03
IDA Pro 자주쓰는 Python 스크립트  (0) 2015.09.03
Posted by Mungsul
,