라이브러리안 사용해 보기(리버스 엔지니어링 1편) - 2009/02/09 16:52

개발 환경 중 컴파일러라고 하면 우리는 흔히 어셈블러(ASSEMBLER), C/C++ 컴파일러(COMPILER), 링커(LINKER)를 떠 올리고 나서 마지막으로 컴파일러에 포함되는 것은 아니지만 디버거(DEBUGGER)도 있다고 얘기 하곤 한다. 디버거가 상용제품 들에는 대개 기본적으로 따라오는 것이기 때문인 듯 하다.

어쨋든 우리가 잘 사용하는 것은 아니지만 위에 열거에는 한가지가 빠져있는데 필자가 금번에 얘기 해 보려는 주제인 라이브러리안(LIBRARIAN) 이라고 하는 놈이다. 개발자들은 맞아 이런 것도 있었지 하면서 손뼉을 칠 바로 그 놈이다.


이제 설명을 위하여 사용할 라이브러리안은 ARM 컴파일러 중 하나인 ADS 제품의 'armar' 이다.
자세한 내용은 해당 매뉴얼을 참조하길 바라며 여기서는 armar 의 간단한 사용법과 주요 기능을 우선 설명하겠다.
쉘프롬프트상에서 armar[ENTER]이라고 입력 해보자. 그러면 다음과 같은 사용법을 설명하는 HELP가 표시된다. 

ARM Archiver, ADS1.2 [Build 805]

       - archive creation and maintenance tool

Command format:
armar options archive [ file_list ]
Wildcards '?' and '*' may be used in file_list
Options:-
-r         Insert files in <file_list>, replace existing members of the same name.
-d         Delete the members in <file_list>.
-x         Extract members in <file_list> placing in files of the same name.
-m         Move files in <file_list>.
-p         Print files to stdout.
-a pos     Insert/move files after file named <pos>.
-b pos     Insert/move files before file named <pos>.
-u         Update older files only, used with -r.

-n         Do not add a symbol table to an object archive.
-s         Force regeneration of archive symbol table.
-t         Print table of contents of archive.
-zs        Show the symbol table.
-zt        Summarize the archive contents (sizes + entries).
-c         Suppress warning when a new archive is created.
-C         Do not overwrite existing files when extracting.
-T         Truncate file names to system maximum length.
-v         Give verbose output.
-create    Force creation of a new archive.
-via file  Take additional arguments from via file.
-sizes     List the size of each member and the library total.
-entries   List sections containing ENTRY points.
-vsn       Print the current Armar Version.
-help      Print this message.

Examples:-
 

armar
에는 여러가지 기능이 있지만 오브젝트 모듈(.o 혹은 .obj)을 합쳐서 라이브러리를 만들어주고, 특정 모듈을 추가, 삭제, 추출, 리스트하는(보여주는) 것이 핵심 기능이 되겠다.

여기에다 특정 모듈에서 사용된 함수 리스트(정확하게는 심볼테이블)를 보여주는 기능도 있는데.

이 기능이 금번 시간에 필자가 설명 하려는 것과 밀접한 관련이 있다.
 
앞으로 몇가지 시도를 해보겠다.
먼저, 표준라이브러리에는 어떤 것들이 들어 있는지 한번 보도록 하자.


ADS 툴의 경우에 라이브러리는 다음의 경로에 위치해 있다.
C:\Program Files\ARM\ADSv1_2\Lib\armlib>
 
ARM라이브러리는 c_a__se.l 등으로 표시되어 파일명에 'a'가 포함되어 있으며 THUMB라이브러리는 c_t__se.l 로서 't'로 표기되어 있는 것을 볼 수 있다.

쉘프롬프트상에 다음과 같이 입력해 본다.

armar -zt c_a__se.l [ENTER]

많은 량의 출력이 화면상에 표시될 것이다.

Code    RO Data    RW Data    ZI Data      Debug   Object Name

       152          0          0          0        116   __dup.o
       168          0          0          0         56   __main.o
       172          0          0          0         56   __main_nshl.o
중략...

        44          0          0          0         80   stats.o
      1648          0          0        204        584   stdio.o
       492          0          0          0        204   stkheap1.o
중략...

       124          0          0          0         88   vsnprintf.o
        96          0          0          0         84   vsprintf.o
        80          0          0          0         80   wcstombs.o
        28          0          0          0         60   wctomb.o
     54664       2788          0       1030      31700   TOTAL

 
ENTRY at offset 0 in section !!! of __main.o
ENTRY at offset 0 in section !!! of __main_nshl.o



표준라이브러리 내의 많은 오브젝트 모듈 모습이 보인다.
익숙한 이름인 '__main.o', ' stdio.o', ' vsnprintf.o' 들이 눈에 띈다.

다음으로는 이 라이브러리(c_a__se.l)에서 'stdio.o' 을 추출하고 이 오브젝트에는 어떤 것들이 들어 있는지 보겠다.
armar -x c_a__se.l stdio.o [ENTER]
 
실행 후 현재 폴더에 stdio.o 파일이 하나 새롭게 보이게 될 것이다.
방금 실행 결과 라이브러리에서 해당 오브젝트 모듈이 추출된 것이다. 한편 라이브러리의 크기나 내용에는 변화가 없다.

stdio.o 만을 구성원으로 하는 새로운 라이브러리(test.l)를 하나 만들겠다.
armar -r test.l stdio.o [ENTER]
 
새로 만들어진 라이브러리test.l의 심볼테이블을 확인하기 위해서는 다음의 옵션('-zs')을 입력한다.
armar -zs test.l [ENTER]

다음과 같이 해당 라이브러리(오브젝트)에서 사용된 변수, 함수가 출력된다.

__stdin              from stdio.o    at offset    256
__stdout             from stdio.o    at offset    256
__stderr             from stdio.o    at offset    256
_seterr              from stdio.o    at offset    256
_writebuf            from stdio.o    at offset    256
_flushlinebuffered   from stdio.o    at offset    256
_fflush              from stdio.o    at offset    256
_deferredlazyseek    from stdio.o    at offset    256
fclose               from stdio.o    at offset    256
freopen              from stdio.o    at offset    256
fopen                from stdio.o    at offset    256
_initio              from stdio.o    at offset    256
_terminateio         from stdio.o    at offset    256


 
이제 'stdio.o' 안에는 우리가 즐겨 사용하는 fopen, fclose, __stdout 같은 류의 함수나 변수가 들어 있는 것을 눈으로 확인 할 수 있게 되었다. 이로써 우리는 대충 라이브러리안이 이런 일을 할 수 있다는 것을 알게 되었다.
 
이를 응용하면 다음과 같은 것도 가능 할 수 있다. 본 글의 주제 이기도 하다.
armar -d c_a__se.l stdio.o [ENTER]
'-d' 옵션은 라이브러리에서 특정 오브젝트 모듈을 삭제하는 명령이다.
 
new_stdio.c 코드를 사용자가 직접 작성하여서 표준라이브러리를 커스터 마이징 할 수 있다.
armar -r c_a__se.l new_stdio.o [ENTER]
여기서의 '-r' 은 라이브러리에 오브젝트를 추가 하는 옵션이다.
 
만약에 사용자가 fopen() 을 재 명명하여 다음과 같이 수정하여 빌드(new_stdio.o) 하여 기존의 'c_a__se.l' 에 추가 시켜 놓았다면?
 
FILE *fopen(const char *filename, const char *mode)
{
static FILE fd;
printf("미안합니당.\");
return & fd;
}
변경 된 ' c_a__se.l' 을 사용 하는 이는 다음과 같은 코드를 실행시 황망한 경우를 당할 수도.
fd= fopen("파일명", "r");
열리 라는 파일은 안 열리고 화면에 "미안합니당." 란 단촐한 메시지 만을 보게 될 것이다.
 
당연히 위의 fopen류의 함수는 함수의 모양(명칭, 인자의 유형 갯수, 리턴유무)이 알려져 있지만 모르는 함수는 짐작으로 때려 맞춰서라도 만들 수는 있다.
 
마지막으로 필자가 라이브러리안을 사용 하여 개발시 문제를 해결한 하나의 사례를 소개 하는 것으로 본 글을 마치려 한다.
일전에 voip 인터넷 전화 장비를 개발 할 즈음에 호(CALL) 처리용 DSP 라이브러리를 사용 하였는데 이상하게도 사용된 호 처리 함수 라이브러리(소위 SDK 라고 하는것)에서 아웃바운드 콜 호출 함수는 지원되는데 반대의 개념인 인바운드 콜 호출 함수가 매뉴얼에 보이질 않는 것이 었다.
이상한 일이 었다.
 
DTMF_OUTBOUND(); DTMF_INBOUND();
예를 들면 위의 함수가 둘 다 있어야 하는데 SDK 매뉴얼 상에는 DTMF_OUTBOUND 만 설명 되어 있고,  DTMF_INBOUND 는 보이질 않는 것이었다.
이 글을 적고 있는 지금와서는 내가 당시 SDK 을 정확히 이해 못해서 그랬던 것으로 생각하고 있고, 믿고 싶지만 어쨋든 당시에는 심각한 문제였다. 늘 상 그렇듯이. . .
업체에 질문도 넣어보고 하다 하다 날만 보내다 어느날 번뜩 떠오르는 것이 있어 즉시 하나의 시도를 해보았다.
armar -zs sdk.l [ENTER]
순간 깜짝 놀랐다. 예상했던 함수 이름인 DTMF_INBOUND 와 정확히 일치하지는 않지만 비슷한 이름의 함수 이름이 보였다. 예를들면 _dtmf_INBOUND 이런식으로 말이다.

아무 생각없이 이 출처 불명의 함수를 DTMF_OUTBOUND와 입/출력 인자(아규먼트)가 같다고 가정하고 그냥 사용 해 보았다.
그런데, 설마. 이 함수가 놀랍게도 내가 원하는 작동을 하는 것이다.
이때 기쁨과 한숨이 동시에 튀어 나온다. 한숨보다는 기쁨이 훨씬 크지만 말이다.
개발 목표 일정은 목전에 다가온 빠듯한 상황에서 가뭄에 단비와도 같은 것이었다.

지금의 소개 글이 바람직한 상황은 절대 아니다. 출처 불명의 코드를 사용하였기 때문이다. 이로써 사후 문제가 발생시 해당 공급 업체(DSP SDK)에서 보상은 물론이고 지원을 받을 수가 없을 지도 모른다.

하지만, 최악의 상황이라는 것은 언제라도 있을 수 있다는 것을 생각해 본다면 이러한 꼼수가 분명 돌파구 역할을 했음은 누구도 인정할 것이라고 생각한다.
 
본 칼럼은 악의적인 편법을 알리려는 의도 보다는 하나의 꼼수를 공유하려는 것이며 임베디드 뿐 아니라 일반적인 소프트웨어 분야에서도 '꼼수'는 특정 상황에서 어떤 문제를 풀어 나가는데 중요한 열쇠가 되기도 한 다는 것을 많은 이들이 또 공감 할 줄로 믿는다.
 
-홍익컴닷컴-
http://www.hongikcom.com 

♡ 포스팅이 유익 하셨다면 E-mail로 가일의 임베디드 스쿨을 구독하세요->

Trackback Address :: http://www.hongikcom.com/trackback/13 관련글 쓰기
Name
Password
Homepage
Secret
< PREV |  1  |  ...  116  |  117  |  118  |  119  |  120  |  121  |  122  |  123  |  124  |  ...  131  |  NEXT >