삽질하는플머

윈도 소켓의 프록시 DLL 만들기

탐구생활/Delphi

며칠 전 우연히 감동적인 강좌를 하나 읽게 되었다. 

 

http://www.codeproject.com/Articles/16541/Create-your-Proxy-DLLs-automatically 

 

양병규 형님이 "API Hooking 요점정리" 의 13번 항목에서 "단순 무식하고 쉽지만 실용성이 없다"고 소개한 그 기술에 무려 "실용성"을 부여하는 강좌 되시겠다. 

 

 

프록시 DLL을 만들 때 가장 어려운(귀찮은) 점은, DLL의 모든 함수에 대해 호출규약과 인자를 맞춰 원래 함수를 불러주는 일인데, 이 강좌에서는 이런 귀차니즘을 "__declspec(naked) " 라는 지시자를 써서 간단하게 해결하고 있다. 이 지시자는 VC++의 x86에서 지원되며, 호출시점의 스택상태를 그대로 유지하는 기능을 가진단다. (이번에 처음 구경함) 

 

델파이에서 이런 효과를 내려면 어떻게 하나 고민해봤는데, 스택 구조만 유지한다면 대충 이렇게 해도 잘 되는군. 

 

procedure Test();

asm

  jmp [원래주소]

end;

 

 

 

몰라도 되는 녀석들은 이런식으로 처리하고, 실제 가로챌 함수들에 대해서만 신경 쓸 수 있다는 얘기. 

 

 

그럼 이걸 어디에 쓰면 좋을까?? 

저 강좌와 마찬가지로 만만한 윈도 소켓 DLL을 가지고 놀아 보자. 

 

소켓 API를 사용하면 대충 wsock32.dll -> ws2_32.dll -> mswsock.dll 의 흐름으로 관련 라이브러리들이 링크된다. 

wsock32나 ws2_32 의 프록시를 어플리케이션과 동일한 디렉토리에 넣어두고 send() 나 recv() 같은 함수를 가로채면 패킷을 쉽게 감청할 수 있다.

 

 

델파이 코드를 뱉도록 강좌의 소스를 살짝 수정해 wsock32, ws2_32에 대한 프록시 DLL 프로젝트 파일을 만들어 보았다. 

 

Winsock_Proxy_Src.7z
다운로드

 

 

 

wsock32.dpr 의 주요부분은 다음과 같다. 

 

 

library wsock32;

 

uses

  Windows, SysUtils;

 
......
 
 

procedure __DLLProc(Reason: Integer);

begin

  case Reason of

    DLL_PROCESS_ATTACH:

    begin

      hl := LoadLibrary(PChar(GetSysDirectory + '\wsock32.dll'));

      if hl = 0 then Exit;

 

      OrgFuncs.Arr[0] :=  GetProcAddress(hl, 'accept');

      OrgFuncs.Arr[1] :=  GetProcAddress(hl, 'bind');

      ......

      OrgFuncs.Arr[73] :=  GetProcAddress(hl, 'AcceptEx');

......
 

// AcceptEx

procedure __E__73__();
asm
  jmp [OrgFuncs.Base + SIZE_OF_FUNC * 73]
end;
 

......

 

exports

  __E__73__ index 1141 name 'AcceptEx',

  __E__74__ index 1142 name 'GetAcceptExSockaddrs';

 

......

 

 

 

원본 DLL과 동일한 이름의 함수들을 Export 하고, 이 함수가 불릴 때 OrgFuncs 변수에 담아둔 원래 함수들의 주소로 점프시키고 있다. 호출시점의 스택구조를 유지하므로 원본 함수의 호출규약이나 인자값, 리턴값도 신경 쓸 필요가 없다. 

 

이제 실제로 AcceptEx 함수의 동작에 간섭해보자. WinSock 유니트를 열어 이 함수가 어떻게 정의되어있는지 배껴온다. 

 

function AcceptEx(sListenSocket, sAcceptSocket: TSocket;

  lpOutputBuffer: Pointer; dwReceiveDataLength, dwLocalAddressLength,

  dwRemoteAddressLength: DWORD; var lpdwBytesReceived: DWORD;

  lpOverlapped: POverlapped): BOOL; stdcall;

 
 
 

 __E__73__() 프로시저를 위 내용 그대로 재정의 해 보자. 

 

 

// AcceptEx

function __E__73__(sListenSocket, sAcceptSocket: IntPtr;

  lpOutputBuffer: Pointer; dwReceiveDataLength, dwLocalAddressLength,

  dwRemoteAddressLength: DWORD; var lpdwBytesReceived: DWORD;

  lpOverlapped: POverlapped): BOOL; stdcall;

type

  TAcceptEx = function (sListenSocket, sAcceptSocket: IntPtr;

    lpOutputBuffer: Pointer; dwReceiveDataLength, dwLocalAddressLength,

    dwRemoteAddressLength: DWORD; var lpdwBytesReceived: DWORD;

    lpOverlapped: POverlapped): BOOL; stdcall;

begin

  // 파라미터 가지고 노는 곳

  // ..........

 

  // 원래 함수 호출

  Result :=

    TAcceptEx(OrgFuncs.Arr[73])(

      sListenSocket, sAcceptSocket,

      lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength,

      dwRemoteAddressLength, lpdwBytesReceived, lpOverlapped

    );

end;

 

 

 

 

호출규약과 인자를 맞추어주고 다시 원래 함수에 그대로 전달하고 있다. TSocket 은 다시 선언하기 귀찮아 원래 타입인 IntPtr 형을 사용했다. 

리턴시 스택을 유지해야 하므로 원래 함수를 호출한 뒤 되도록 아무 일도 하지 말자. 지역변수 선언 또한 금물이니 주의하자. 

 

 


 

2016.06.28 추가. 

 

dumpbin 으로 얻어진 TXT 파일을 줏어담는것은 아무래도 모양이 빠져서... 

독립적으로 실행되는 간단한 유틸리티를 만들어 보았다. 이름하여 "프록시 DLL 생성기"

 

 

 

ProxyDllGen.7z
다운로드

 

 

실행시키고 DLL을 끌어다 던지면 Export 된 함수 목록을 보여준다. 

"Generate" 버튼을 누르면 해당 DLL의 델파이 버전 프록시 코드를 생성해준다. 

 

라자루스로 만들어봤는데, 못 본 사이에 참 좋아졌다. 터보델파이를 대체하기에는 조금 아쉽지만...

 

 


 

2017. 02.16

 

github 에 코드 올려둠. 

https://github.com/oranke/proxy-dll-generator

 

 

요물덩어리 emscripten. 세번째.

탐구생활/WEB 관련
텍스쳐를 부르기 위해 zlib 링크. 
간단할 줄 알았는데... 문서대로 되는 게 거의 없네... 
결국 해법은 "emcmake cmake"...  

아무튼 이제야 뭔가 동작하는 것 처럼 보인다. 

처음에는 단순히 예전에 써먹던 고정파이프 방식을 처리하는 셰이더면 충분하다 싶었는데
가지고 놀다 보니 이거 참 편하고 좋은 물건이었군... 


화면 클릭, 우클릭은 Y축 회전.
W키는 와이어 프레임.
L키는 조명 테스트. 

(가끔씩 github.io 가 반응이 없네...)


 



2017.3.30. 

컴파일결과를 올려놓았던 구글드라이브 호스팅이 작년 언제쯤부터 정지되어 먹통이었는데... 

차일피일 미루다 github.io 로 이동시킴. 


요물덩어리 emscripten. 두번째.

탐구생활/WEB 관련

VBO, IBO 붙이고 행렬스텍과 초간단 조명 구현. 
모델은 뭘 쓸까 하다가... "개발자에게 배우는 게임 개발 테크닉" 에 들어있던 ASE를 변환해 붙여봄. 

네이티브에서는 대충 굴러가는 코드가 emscripten으로 빌드만 하면 까탈스럽게 에러를 토해내는데
그래도 삽질하면 어찌어찌 돌아가기는 하네. 

황당했던 경험에 순위를 매겨보면... 
1. char 세 개로 패킹한 노멀좌표가 끼어있으면 정점 stride가 먹지 않음. 정점 구조체 크기는 4의 배수여야 함. 

2. std::vector 만 쓰면 쏟아지던 에러. library-glfw.js 내부에 공백대신 낑궈져있던 문자를 지워 해결. 

3. 셰이더에 보낸 정점은 셰이더 내에 어떤 형태로든 써먹어주어야 함. 안그러면  아무것도 표시 안됨. 


이제 텍스쳐만 발라주면 그럴듯하겠다. 




화면 클릭, 우클릭은 Y축 회전.
W키는 와이어 프레임.
L키는 조명 테스트. 




요물덩어리 emscripten

탐구생활/WEB 관련

요물덩어리 emscripten 가지고 노는 중. 

좀 더 멋진 예제였으면 좋겠지만... 
고정파이프라인에 익숙한 구닥다리에게 셰이더는 고문이다. 

일단 뷰, 프로젝션, 버텍스만 받게 해서 뱅뱅 돌려봄.

emscripten 1.25.0 
OpenGL ES 2.0 
GLFW 3.0 의 event.c 예제기반. 


[티끌팁] MySQL 테이블 구조 엑셀로 출력

탐구생활/WEB 관련

블로그에 쌓인 먼지 털기용으로 올리는 티끌만한 팁. 


MySQL의 테이블 구조를 엑셀로 정리하라는 요청을 받음. 

스키마 생성 SQL만 던져주면 딱 좋겠지만, 세상 모든 사람이 개발자는 아니니... 


수백개의 테이블을 하나 하나 예쁘게 정리하는 작업은... 막내에게 시킨다고 해도 입이 한 뼘은 튀어나올 일... 

뭐 좀 편한방법이 없을까 구글신께 의탁하니 다음 신탁을 내려주신다. 


http://sourceforge.net/projects/exportmysqldbst/


오호~ 입맛 당기는데??


테이블을 만들어 테스트 해 보자. 

1 CREATE TABLE  `testdb`.`testtbl` (
2   `ID` INT NOT NULL COMMENT  '아이디',
3   `Name` VARCHAR( 30 ) NOT NULL COMMENT  '이름',
4   `Desc` TEXT NOT NULL COMMENT  '설명'
5 ) ENGINE = MYISAM COMMENT =  '테스트DB';


결과는 흐음... 




약간 아쉽지만 쓸만하다고 생각했는데...

깐깐한 요구자는 필드 설명도 달아달라네. 필드타입도 길이와 분리되었으면 좋겠다고 하고... 


해서 뚝딱뚝딱 수정한 물건. 


MySQL_DB_Structure_to_Excel.7z



SHOW COLUMNS 대신 INFORMATION_SCHEMA.COLUMNS 을 사용했고, 

UTF-8을 인식하지 못하는 엑셀을 위해 리틀엔디안 형식의 UCS-2로 출력한다. 


기존 dbDesingExport.php 대신 수정한 dbDesingExport2.php 를 사용해 출력한 결과는 다음과 같다. 






이제 막내에게 색깔 대충 입히고 줄 몇 개 그어주게 하면... 업무 종료~ ^^