[ 리버싱 / 프로그래밍 / 음악 / 게임 / 그 외... ]



월요일, 1월 30, 2017



리버싱을 하다보면 필요에 따라 자신만의 툴을 만드는 경우가 종종 있습니다.

툴을 만들다보면 윈도우 API 를 사용해야 할 때가 있는데...

파이썬에서 ctypes 로 윈도우 API 를 사용하는 방법을 정리해봤습니다.


우선은 ctypes 와 ctypes.wintypes(자료형 모음) 를 임포트 해줍니다.

from ctypes import *
from ctypes.wintypes import *


윈도우 API  는 대체로 windll 을 이용하면 되는데요~

아래처럼 모듈 이름과 함수 이름을 적어주면 됩니다.

# Type 1
GetModuleFileName = windll.kernel32.GetModuleFileNameW
GetModuleHandle = windll.kernel32.GetModuleHandleW

# Type 2
Kernel32 = windll.kernel32

GetModuleFileName = Kernel32.GetModuleFileNameW
GetModuleHandle = Kernel32.GetModuleHandleW


입력하기 쉽게 "GetModuleFileName", "GetModuleHandle" 로 했을 뿐...

windll.kernel32.GetModuleFileNameW / Kernel32.GetModuleFileNameW 이나

windll.kernel32.GetModuleHandleW / Kernel32.GetModuleHandleW 를 그대로 사용해도 됩니다.

사용하려는 API 가 많을 경우 Type 2 처럼 사용하는게 더 편하지 않을까 생각되네요 ^^;;;


API 사용 예 #1 - GetModuleHandleW

from ctypes import *
from ctypes.wintypes import *

Kernel32 = windll.kernel32

print("[*] GetModuleHandleW [*]")
Kernel32_BaseAddr = Kernel32.GetModuleHandleW("KERNEL32.DLL")
print("    - KERNEL32.DLL = 0x%X" % Kernel32_BaseAddr)

GetModuleHandleW 호출 결과

가장 단순한 형태의 사용 예입니다. 그냥 인자를 넣어주기만 하면 되는거죠~ :)

참고로 64비트 파이썬에서는 GetModuleHandleW 를 호출하기 전에...

restype 을 직접 지정해줘야 주소값을 제대로 가져옵니다.

Kernel32.GetModuleHandleW.restype = c_void_p
Kernel32_BaseAddr = Kernel32.GetModuleHandleW("KERNEL32.DLL")


API 사용 예 #2 - GetModuleFileNameW

from ctypes import *
from ctypes.wintypes import *

Kernel32 = windll.kernel32

path = create_unicode_buffer(MAX_PATH)

print("[*] GetModuleFileNameW [*]")
Kernel32.GetModuleFileNameW(0, path, MAX_PATH)
print("    - Path = %s" % path.value)

GetModuleFileNameW 호출 결과

윈도우 API 중에는 GetModuleFileName 처럼 데이터를 담을 버퍼를 인자로 받아서

그 버퍼에 데이터를 넘겨주는 방식도 있습니다.


create_string_buffer, create_unicode_buffer 로 데이터를 담을 수 있는 객체를 만들 수 있는데요...

create_string_buffer 는 C 언어의 "char *", 파이썬의 "bytes" 와 대응되며,

create_unicode_buffer 는 C 언어의 "wchar *", 파이썬의 "str" 과 대응됩니다.

~A 계열 함수를 사용할 때는 create_string_buffer 를 사용하고,

~W 계열 함수를 사용할 때는 create_unicode_buffer 를 사용하면 됩니다.

객체에 담겨진 실제 데이터는 value 를 통해 얻을 수 있습니다.

create_string_buffer / create_unicode_buffer


API 사용 예 #3 - CreateProcessW

from ctypes import *
from ctypes.wintypes import *


class PROCESS_INFORMATION(Structure):
    _fields_ = [("hProcess", HANDLE),
                ("hThread", HANDLE),
                ("dwProcessId", DWORD),
                ("dwThreadId", DWORD)]


class STARTUPINFO(Structure):
    _fields_ = [('cb', DWORD),
                ('lpReserved', LPWSTR),
                ('lpDesktop', LPWSTR),
                ('lpTitle', LPWSTR),
                ('dwX', DWORD),
                ('dwY', DWORD),
                ('dwXSize', DWORD),
                ('dwYSize', DWORD),
                ('dwXCountChars', DWORD),
                ('dwYCountChars', DWORD),
                ('dwFillAttribute', DWORD),
                ('dwFlags', DWORD),
                ('wShowWindow', WORD),
                ('cbReserved2', WORD),
                ('lpReserved2', LPBYTE),
                ('hStdInput', HANDLE),
                ('hStdOutput', HANDLE),
                ('hStdError', HANDLE)]


Kernel32 = windll.kernel32

startupinfo = STARTUPINFO()
processinfo = PROCESS_INFORMATION()

print("[*] CreateProcessW [*]")
Kernel32.CreateProcessW("C:\\Windows\\NOTEPAD.exe", None, None, None, 0, 0,
                        None, None, byref(startupinfo), byref(processinfo))
print("    - hProcess = %X" % processinfo.hProcess)
print("    - dwProcessId = %d (%X)" % (processinfo.dwProcessId, processinfo.dwProcessId))

CreateProcessW 호출 결과

앞의 두 예제와 비교하면 코드의 양이 꽤 깁니다...;;; ( 이게 다 구조체 때문임.. =_=;;;; )


파이썬은 C 언어의 '구조체' 를 그대로 사용할 수 없기 때문에...

'구조체' 를 인자로 받는 API 를 사용하기 위해서는 추가 작업이 필요합니다.

ctypes 의 "Structure" 클래스를 상속받아서 임의의 클래스를 만든 다음...

"_fields_" 에 구조체 멤버들을 추가해주면 됩니다.

함수 인자에 참조 연산자('&')를 사용하는 경우가 있는데 파이썬은 "byref" 를 이용하면 됩니다.



이상의 세가지 형태의 API 사용 방법을 숙지하고 있으면...

대부분의 윈도우 API 는 문제없이 사용할 수 있을거라 생각합니다. @_@;;;





화요일, 1월 24, 2017



프로그래밍 전문잡지 "마이크로소프트웨어" 가 다시 돌아왔습니다 :)

예전처럼 월간지 형식은 아니지만 그래도 종이로 인쇄된 책을 넘겨볼 수 있다는 건 정말 반갑네요 ^^


2017년 vol.387


1997년...

같이 놀던 친구의 영향으로 프로그래밍에 관심을 갖기 시작하면서~

프로그래밍 관련 책들을 보기 시작했는데 "마이크로소프트웨어" 도 그 중 하나였습니다.

그 당시는 책 내용을 거의 이해못했던 기억이 나네요... ^^;;;

C 언어 공부를 막 시작했고 printf() 로 문자열 출력하는 것만으로 신세계를 경험했던 수준에서는

너무 어려웠달까요...;;;

1년 정도 지난 후, 기반 지식이 조금 쌓인 후에야 처음에 봤던 내용들이 이해가 가더군요 @_@;;

그 후로는 지금 당장은 어려워도 나중엔 도움이 되겠지 생각하고 정기구독을 하기도 했습니다.
( 실제로 시간이 조금 지난 후에 그 내용들이 도움이 되었다는게... )


2000년 조금 지난 시점에는 "웹" 이 유행하기 시작하면서...

마소의 내용도 웹프로그래밍, DB 등 분야가 다양해지더군요.

책 한 권에 담을 수 있는 내용의 양은 정해져 있는데, 다루는 분야가 넓어진 만큼...

원하는 내용이 많이 줄어드는 걸 느꼈습니다.

책 한 권 안에 볼 내용이 하나도 없는 경우도 있더군요...;;;


그 후로 회사 생활을 시작하면서 회사에서 정기구독을 하면 회사에서 보고~

업무 분야(보안, 리버싱 등...)의 내용이 담기거나 지인이 기고를 하면 한번씩 구매를 했네요..;;

어쨌든 필요한 정보도 얻고 나름 도움도 받았던 잡지가 2015년 12월을 마지막으로 휴간되더군요.
( '휴간'이라 쓰고 '폐간' 이라 읽... )


2015년 마소들


휴간 결정이 난 후로 많은 분들이 아쉬워했고 다시 살리려는 움직임도 많았던 걸로 알고 있는데...

그 결실이 이렇게 맺어진 게 아닌가 싶네요... :)


프로그래밍 전문잡지의 명맥이 계속 유지될 수 있길...





금요일, 1월 20, 2017



대세 드라마 "도깨비" 의 OST 입니다.

멜로디 라인이 제대로 취향저격을...ㅜㅜ...

얼마간 무한반복 할 듯 싶네요.






에일리 - 첫눈처럼 너에게 가겠다

널 품기 전 알지 못했다
내 머문 세상 이토록
찬란한 것을

작은 숨결로 닿은 사람
겁 없이 나를 불러준 사랑

몹시도 좋았다
너를 지켜보고 설레고
우습게 질투도 했던
평범한 모든 순간들이

캄캄한 영원
그 오랜 기다림 속으로
햇살처럼 니가 내렸다

널 놓기 전 알지 못했다
내 머문 세상 이토록
쓸쓸한 것을

고운 꽃이 피고 진 이 곳
다시는 없을 너라는 계절

욕심이 생겼다
너와 함께 살고 늙어가
주름진 손을 맞잡고
내 삶은 따뜻했었다고

단 한번 축복
그 짧은 마주침이 지나
빗물처럼 너는 울었다

한번쯤은 행복하고
싶었던 바람
너까지 울게 만들었을까

모두, 잊고 살아가라
내가 널, 찾을 테니
니 숨결, 다시
나를 부를 때

잊지 않겠다
너를 지켜보고 설레고
우습게 질투도 했던
니가 준 모든 순간들을

언젠가 만날
우리 가장 행복할 그날
첫눈처럼 내가 가겠다

너에게 내가 가겠다



수요일, 1월 11, 2017



일전에 '스카이림 스페셜 에디션' 관련된 내용을 올린 적이 있습니다.

http://www.xeronichs.com/2016/11/SkyrimSE-Achievements-with-MOD.html ]


모드 적용 시 업적 달성 가능하도록 해주는 툴을 만들어야지... 만들어야지... 하다가

요 며칠간 뚝딱뚝딱 만들어봤습니다.


UI 작업할 땐 개인적으로 C++ Builder 를 더 좋아하는데~

스카이림 스페셜 에디션이 64비트 클라이언트라서 어쩔 수 없이 Visual Studio 로..;;;;

( 현재 보유 중인 C++ Builder 스타터 에디션은 64비트를 지원하지 않다보니.. oTL;;; )

예전에는 MFC 도 그럭저럭 썼던거 같은데... 오랜만에 만져보니 뭔가 번거롭더군요..

특히 컨트롤 크기나 배치 등 설정을 세밀하게 하는게 C++ Builder 에 비해서 귀찮습니다;;;




스카이림 실행 파일("SkyrimSE.exe") 파일의 경로를 지정해주고~

"Patch (with Run)" 버튼을 누르면 게임 실행과 동시에 패치를 해줍니다.


참고로 실행 파일을 직접 패치하는 게 아니라 실행된 프로세스의 메모리 코드를 패치하는거라서...

매번 -_-;;; 실행을 해줘야 합니다...

일단 제가 원하는 선에서는 잘 동작하는 관계로 기능 추가가 있을지는 모르겠네요..ㅋㅋ ^^;;;


[ SkyrimSE_AE_Patch 다운로드 ]

[ Visual Studio 2015 재배포 패키지 ]




수요일, 12월 07, 2016



며칠 전입니다...

익명의 어느 분께서 x64dbg 로 crackme 실행파일을 열면 Crash 가 발생한다며...

혹시 그 이유를 아는지 블로그 댓글로 질문을 하셨습니다.

( 참고 - http://www.xeronichs.com/2016/11/attach-helper-x64dbg-plugin.html )

같은 OS 환경인데도 제 PC 에서는 별다른 문제가 없었기에...

플러그인 문제나 다른 외부 프로그램과 충돌이 아닐까~ 추측만 하고 넘어갔었습니다...


이번에 다른 분께서 동일한 문제가 발생한다며 댓글을 남기셨고...

그 분 나름대로 문제가 발생하는 부분까지 찾아내셨습니다... @_@ ;;;

11월 5일 2번째 릴리즈(snapshot_2016-11-05_19-55.zip) 이후로  언어를 '한글' 로 설정하면...

실행파일을 불러올 때 Crash 가 발생한다고 하시더군요.

저는 x64dbg 언어 설정을 처음부터 "영어" 로 맞춰두고 사용을 하다보니 문제가 발생하지 않았던거구요.. ^^;;

확인 차 언어 설정을 '한글' 로 잠깐 바꿔봤더니 Crash 가 발생하더군요... oTL;;;

언어 설정 "한글" 로 하면 파일을 열 때 Crash 발생

조금 더 정확하게 설명하면 x64dbg -> Settings 에서 Events 탭에...

"Entry Breakpoint*"  가 체크가 되어있을 때 Crash 가 발생합니다...

"System Breakpoint*" 를 체크하고 "Entry Breakpoint*" 를 체크하지 않으면 실행이 잘 되더군요..;;

한글 언어 적용 후, "Entry Breakpoint*"  체크 시 Crash 발생


언어 설정을 '영어' 로 하면 문제가 없고, '한글' 로 하면 Crash 발생하는 건...

언어 파일 자체에 뭔가 문제가 있다고 볼 수 있겠죠...

실제로 Crash 문제가 발생하기 시작한 11월 5일 두번째 릴리즈의 한글 언어 파일과...

문제가 발생하지 않는 한글 언어 파일을 비교하면 파일 크기 차이가 꽤 납니다... ;;;

왼쪽은 Crash 발생하지 않는 버전, 오른쪽은 Crash 발생하는 버전

한글 언어 파일에 내용이 추가되면서 뭔가 문제가 생긴 것 같아서 그 부분을 분석해봤습니다.


디버거 UI 에 언어 파일을 적용해주는 함수

위의 함수에서 "GuiTranslateText" 함수를 이용해 현재 적용된 언어 파일의 내용을 구해오도록 되어 있더군요.


Crash 발생하는 원본 문자열

분석한 결과 "%s breakpoint "%s" at %s (%p)!" 라는 문자열을 한글로 출력하려고 할 때...

Crash 가 발생했습니다.

포맷스트링 %s, %s, %s, %p 가 사용되고 이에 대한 실제 값은 ESI(0xA19DCE8)에 있습니다.

포맷스트링 실제 값

첫번째 %s = "INT3"
두번째 %s = "entry breakpoint"
세번째 %s = "<asmjit.EntryPoint>"
네번째 %p = 0x5801EA22

언어 설정이 '영어' 일 때 아래와 같은 문자열이 완성됩니다.

INT3 breakpoint "entry breakpoint" at <asmjit.EntryPoint> (5801EA22)!


언어 설정이 '한글' 인 경우에는...

"%s breakpoint "%s" at %s (%p)!" 문자열이 아래와 같이 변경됩니다.

한글 적용 시 변경된 문자열

한글로는 "%s (%p) 에 %s 중단점 "%s"!" 라는 내용이 됩니다. ( oTL;;;; )


원래 포맷스트링의 순서는 %s, %s, %s, %p 인데...

한글 언어 파일의 내용에는 %s, %p, %s, %s 로 되어있네요.. @_@..!?!?

이 내용이 "_vsnprintf_s" 함수로 들어가면~

마지막 %s 가 엉뚱한 곳에서 문자열을 가져오려고 하다가 실패하고 Crash 가 딱~!!;;

엉뚱한 곳에서 문자열을 찾으려고 함


이 부분이 정상적으로 동작하려면 한글 언어 파일의 포맷스트링도 %s, %s, %s, %p 의 순서로 되어야 됩니다.


일단 제가 확인한 부분은 이 부분인데 다른 부분도 포맷스트링 순서가 일치하지 않을 경우...

얼마든지 Crash 가 발생할 수 있습니다. @_@;;;

한글 언어 파일 만드신 분이 번역을 조금 더 자연스럽게 하려고 하다가...

포맷스트링 부분은 미처 확인 못해서 이런 문제가 발생한게 아닌가 싶네요...

얼른 문제가 수정될 수 있길...





수요일, 11월 23, 2016



나름 DOS 시절부터 컴퓨터를 사용해서 그런지 모르겠지만...

아직까지 '마우스' 보다는 '키보드' 가 더 편하게 느껴집니다.

꼭 마우스를 이용해야 하거나 마우스가 더 편리한 작업이 아닌 이상...

웬만해선 키보드로 다 작업을 하는데요.

그러다보니 '단축키' 를 많이 활용하는 편입니다.


얼마 전 일입니다...

Visual Studio 로 작업하다가 프로젝트 속성을 변경하려고 "Alt-F7" 을 눌렀는데...

오잉...!? 반응이 없더군요 @_@;;;;;

메뉴에서 직접 실행하면 '프로젝트 속성' 창이 잘 뜨는데

단축키 "Alt-F7" 을 누르면 꿀먹은 벙어리 마냥 반응이 없었습니다.

뭔가 Visual Studio 시스템이 꼬인건가 싶어 이것저것 살펴봤지만 별다른 수확은 없었고

찜찜한 마음에 포맷까지 하게 됐습니다 ~ oTL;;;;


운영체제랑 프로그램 새로 다 설치하고~

산뜻한 마음으로(?) 기분좋게 Visual Studio 를 실행시켜 "Alt-F7" 을 눌러봤는데...

헐...!? 여전히 단축키가 안먹힐 때의 그 멘붕이란...;;;

뭐... 조금 불편하긴 하겠지만 포맷도 했겠다~ 다른 문제는 없는 듯 싶어 넘겼습니다.


그로부터 며칠 후...

별 생각없이 게임을 실행했는데 그날따라 유독~

게임 시작 시 화면에 잠깐 나왔다 사라지는 NVIDIA 메시지가 신경쓰이더군요.

"Alt-Z" 를 누르면 된다길래 눌러봤더니...

NVIDIA GeForce Experience 의 화면이 뜨더군요.

이건 뭔가 싶어 이것저것 둘러보던 중 단축키 부분을 발견..;;;;

맙소사... "Alt-F7" 이 GeForce Experience 의 단축키로 딱 있더군요


NVIDIA GeForce Experience 의 단축키들

GeForce Experience 의 단축키들이 전역으로 동작하는 바람에...

Visual Studio 의 "Alt-F7" 이 그냥 무시된 걸 알았을 때의 그 허탈함이란...


조금 더 만지작 거려보니 저 기능은 "공유" 기능이 켜져있을 때만 동작을 하더군요.

NVIDIA GeForce Experience 의 공유 기능

딱히 게임하는 순간을 스트리밍하거나 할 일은 없을 것 같아서 과감하게  Off~~!!

'공유' 기능을 꺼둔 상태에서는 Visual Studio 에서 "Alt-F7" 이 잘 동작하더군요... 하아 =3=3

( 내가 이러려고 포맷을 했나.... 싶은;;; oTL )


혹시라도... GeForce Experience 를 설치한 불특정 다수(?)의 개발자 분들이

일부 단축키가 안먹히는 상황에 저같은 뻘짓을 하지않길 바라면서 살포시 공유해봅니다.




화요일, 11월 15, 2016



얼마 전, 네이버 블로그 첨부파일을 다운로드 받는 파이썬 코드를 작성했는데요...

자매품으로(?) 티스토리 첨부파일을 받는 코드도 만들어봤습니다. ^^;;;;

Win95/98 용 고전 게임들 찾다보면 첨부파일이 어마어마하게 많은 경우가 있는데...

하나하나 클릭하기 귀찮아서 코딩까지 하게 되었네요~ ^^;;;;


네이버 블로그는 첨부파일 정보가 있는 페이지까지 접근하기가 좀 귀찮을뿐(?)

그 페이지까지 접근만 하면 첨부파일 다운로드는 비교적 쉽게(?) 해결이 됩니다.

"aPostFiles" 라는 자바스크립트 배열이 있고 그 안에 모든 첨부파일의 정보(링크, 파일이름, 크기 등...)가

가지런히 담겨져 있기에 해당 배열의 내용만 잘 가져오면 되거든요 :)


티스토리는 처음에 접근하는 페이지에 첨부파일 정보가 바로 있어서~

첨부파일 정보를 확인하는 건 어렵지 않습니다.

그런데 네이버 블로그처럼 첨부파일 정보가 한 곳에 몰려있는게 아니라...

<a href="첨부파일 링크"> .... 파일이름</a>
형태로 포스팅 내용 전역에 걸쳐서 포함될 수 있기에 이걸 처리하는게 좀 귀찮습니다. -_-;;;

( 전 그냥 페이지 전체 소스에서 '첨부파일 링크' 를 포함한 태그를 모조리 찾는 방법으로 해결을.. -_-;;;; )


[ GitHub - https://github.com/XeroNicHS/GMF ]

# GMF [File Downloader] for Tistory Blog

import re
import sys
from http import client
from urllib import request


def print_logo():
    print("#------------------------------------------#")
    print("# [GMF] Give Me a File!! [File Downloader] #")
    print("#------------------------------------------#")
    print("# for Tistory Blog\n")


def get_url_source(url):
    try:
        f = request.urlopen(url)
        url_info = f.info()
        url_charset = client.HTTPMessage.get_charsets(url_info)[0]
        url_source = f.read().decode(url_charset)

        return url_source

    except Exception as e:
        print("[-] Error : %s" % e)
        sys.exit(-1)


def main():
    print_logo()

    if len(sys.argv) != 2:
        print("[*] Usage : gmf_ti.py [Tistory Blog URL]")
    else:
        url = sys.argv[1]
        print("[*] Target URL : %s\n" % url)
        url_source = get_url_source(url)

        # find 's1.daumcdn.net/cfs.tistory'
        if url_source.find("t1.daumcdn.net/tistory") == -1:
            print("[-] It is not a Tistory Blog")
            sys.exit(0)

        try:
            # find all 'attach file link'
            p_attach = re.compile(r"href=[\'\"](\S+?/attachment/.*?)[\'\"]\s*.*?/> (.*?)</", re.IGNORECASE | re.DOTALL)
            result = p_attach.findall(url_source)

            if result:
                for each_file in result:
                    file_url = each_file[0]
                    if each_file[1] == "":
                        file_name = file_url[file_url.rfind('/') + 1:]
                    else:
                        file_name = each_file[1]
                    print("* File : %s" % file_name)
                    print("  Link : %s" % file_url)
                    request.urlretrieve(file_url, file_name)
                    print("  ==> Done")
            else:
                print("[-] Attached File not found !!")

        except Exception as e:
            print("[-] Error : %s" % e)
            sys.exit(-1)

if __name__ == "__main__":
    sys.exit(main())

gmf_ti.py 실행

티스토리 첨부파일 태그의 모든 형태를 다 확인한게 아니라...

경우에 따라서는 정보를 못가져올 수도 있습니다... @_@;;;;




카테고리

가장 많이 본 글

통계

Copyright © XeroNic(HS) BLOG | Powered by Blogger
Design by WP Lift | Blogger Template by NewBloggerThemes.com