배열 과 함수 포인터 형변환에 관해서..
글쓴이: oprsystem / 작성시간: 월, 2004/03/08 - 4:15오후
안녕하세요..
함수를 배열로 복사한뒤에 배열을 함수 포인터의 주소로 옴겨서 실행하려고 합니다.
테스트 해 보기위해서 VC6.0에서 작성하였습니다.
작성한 파일의 확장자는 CPP입니다.
제가 무엇을 잘못 하였는지 지적 부탁드리겠습니다.
int (*ramfunction)();
unsigned long RAM_FUNC_AREA[1000];
int RamFunc();
int EndRamFunc();
int main(int argc, char* argv[])
{
memcpy((char *) RAM_FUNC_AREA,(char *) RamFunc,
(int)((unsigned long)EndRamFunc - (unsigned long) RamFunc));
ramfunction = (int(*)())RAM_FUNC_AREA;
ramfunction();
return 1;
}
int RamFunc()
{
printf("HI RAM AREA");
return 1;
}
int EndRamFunc()
{
#if 0
DUMMY
#endif
return 1;
}[/b]Forums:


기발한 아이디어입니다.안타깝게도.. 실행 불가능합니다.함수
기발한 아이디어입니다.
안타깝게도.. 실행 불가능합니다.
함수의 크기를 계산할 수 있는 방법은 존재하지 않으며,
함수의 내용을 변수에 복사하는 방법도 존재하지 않으며, 복사를 했다고 하더라도 그 코드를 실행할 수 있는 방법도 존재하지 않습니다.
이런 아이디어가 필요하시다면 C 대신에 lisp이나 scheme을 쓰시기 바랍니다.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Korean Ver: http://cinsk.github.io/cfaqs/
함수 포인터.
함수 포인터의 개념에 대해 잘못 생각하신듯 합니다.
일단 간단히 님의 소스를 변경해 보았는데.
이해를 도와줄 것입니다.
typedef int (*FUNC_PTR)(void); FUNC_PTR RAM_FUNC_AREA[1000]; int RamFunc(); int EndRamFunc(); int main(int argc, char* argv[]) { RAM_FUNC_AREA[0] = &RamFunc; RAM_FUNC_AREA[0](); return 1; } int RamFunc() { printf("HI RAM AREA"); return 1; } int EndRamFunc() { #if 0 DUMMY #endif return 1; }[quote="cinsk"]기발한 아이디어입니다.안타깝게도.. 실
음.. 저도 좀의문을 가졌었는데..
함수포인터의 주소는 실제 코드가 저장된위치가 아닌모양이지요..
----------------------------------------------------------------------------
안녕하세요..벌써 답글이 3개나 달렸네요.. 관심 감사 합니다.
안녕하세요..
벌써 답글이 3개나 달렸네요.. 관심 감사 합니다.
제가 미리 밝혔어야 하는데.. 저 코드는 저의 아이디어가 아니라 "Firmware Demystified" 라는 책에서 발췌한 내용 입니다. 제 불찰 입니다. 죄송합니다.
그리고.. 아직 해결 하지 못했습니다. :roll:
황혼보다 어두운 자여
내 몸에 흐르는 피보다 더 붉은 자여
시간의 흐름 속에 파뭍힌 위대한 그대의 이름을 걸고 나 여기서 어둠에 맹세하노라
우리 앞을 가로막고 있는 모든 어리석은 자 들에게
나와 그대의 힘을
위대한 파멸의 힘을 보여줄 것을
C++이라면
함수 포인터 대신에 함수 객체(function object)를 쓰면 가능하지요.
검색해보시길...
재밌는 기능인데, 제 생각은 함수 내의 내용에 따라 실행 되는 함수도 있
재밌는 기능인데, 제 생각은 함수 내의 내용에 따라 실행 되는 함수도 있을 것 같고 그렇지 않은 함수도 있을 것 같습니다.
즉, OS나 컴파일러등 여러 환경에 따라 특정 상태에서만 실행될 것이라는 얘기 입니다.
data segment가 실행가능한 경우가 보장되어야하고 (2004년 현재 대부분 그렇죠?)
이름이 뭐하지만, 대충 지어본다면 User level re-location 으로도 안전한 코드여야하고..
몇몇 조건만 만족하면 실행가능한 코드도 찾아 볼 수 있을 것 같은데요?
---
http://coolengineer.com
가능하지 않을까요?buffer overflow 코드들도 어셈으로
가능하지 않을까요?
buffer overflow 코드들도 어셈으로 작성되어 stack 메모리에서 실행하는 구조이니..
어셈으로 원하는 기능을 모두 구현하려면 꽤 힘들것 같기는합니다.
[code:1]#include <stdio.h>int &#
#include <stdio.h> int (*ramfunction)(); unsigned long RAM_FUNC_AREA[1000]; int RamFunc(); int EndRamFunc(); int main(int argc, char* argv[]) { memcpy((char *) RAM_FUNC_AREA,(char *) RamFunc, (int)((unsigned long)EndRamFunc - (unsigned long) RamFunc)); ramfunction = (int(*)())RAM_FUNC_AREA; ramfunction(); return 1; } int RamFunc() { int (*print)(const char *,...) = printf; (*print)("HI RAM AREA"); return 1; } int EndRamFunc() { #if 0 DUMMY #endif return 1; }이렇게 하면 잘되는군요..! 왜 그런지는 assembly code를 잘 살펴보면 됩니다...
힌트는 메모리 이동이 일어나는 함수 안에는 상대 점프가 일어나지 않아야합니다.
---
http://coolengineer.com
아. .그렇군요..
아. .그렇군요..
황혼보다 어두운 자여
내 몸에 흐르는 피보다 더 붉은 자여
시간의 흐름 속에 파뭍힌 위대한 그대의 이름을 걸고 나 여기서 어둠에 맹세하노라
우리 앞을 가로막고 있는 모든 어리석은 자 들에게
나와 그대의 힘을
위대한 파멸의 힘을 보여줄 것을
혹시 아래의 에러에 대해 솔류션을 가지신분 없으신가요? (VC++6.0)
혹시 아래의 에러에 대해 솔류션을 가지신분 없으신가요? (VC++6.0)
C:\Program Files\Microsoft Visual Studio\MyProjects\aaasss\aaasss.cpp(22) : error C2440: 'type cast' : cannot convert from 'unsigned long [1000]' to 'int (__cdecl *)(void)'
There is no context in which this conversion is possible
Error executing cl.exe.
황혼보다 어두운 자여
내 몸에 흐르는 피보다 더 붉은 자여
시간의 흐름 속에 파뭍힌 위대한 그대의 이름을 걸고 나 여기서 어둠에 맹세하노라
우리 앞을 가로막고 있는 모든 어리석은 자 들에게
나와 그대의 힘을
위대한 파멸의 힘을 보여줄 것을
암시적 형변환이 일어나게 했나보죠?
암시적 형변환이 일어나게 했나보죠?
---
http://coolengineer.com
ramfunction = (int(*)())RAM_FUNC_AREA;
ramfunction = (int(*)())RAM_FUNC_AREA;
이런식으로 했습니다. VC++에서 나오는 에러네요
다른컴파일러는 그냥 넘어 가는데..
황혼보다 어두운 자여
내 몸에 흐르는 피보다 더 붉은 자여
시간의 흐름 속에 파뭍힌 위대한 그대의 이름을 걸고 나 여기서 어둠에 맹세하노라
우리 앞을 가로막고 있는 모든 어리석은 자 들에게
나와 그대의 힘을
위대한 파멸의 힘을 보여줄 것을
제가 지금 VC가 없어서... 확인을 못하겠군요.. :)
제가 지금 VC가 없어서... 확인을 못하겠군요.. :)
---
http://coolengineer.com
:D
:D
황혼보다 어두운 자여
내 몸에 흐르는 피보다 더 붉은 자여
시간의 흐름 속에 파뭍힌 위대한 그대의 이름을 걸고 나 여기서 어둠에 맹세하노라
우리 앞을 가로막고 있는 모든 어리석은 자 들에게
나와 그대의 힘을
위대한 파멸의 힘을 보여줄 것을
[quote="바람돌이"]ramfunction = (int(*)())RA
에러메시지처럼 'unsigned long [1000]'를 바로 'int (__cdecl *)(void)'로 바꾸지는 못합니다.
다음처럼 중간에 void*를 경유하게 해 보세요.
ramfunction = (int(*)())(void*)RAM_FUNC_AREA;일단 에러는 나지 않을 겁니다.
그리고, 위의 코드를 windows상에서 실행시켰더니, 실행이 되질 않습니다.
문제를 찾아보니, 실제 코드영역으로부터 데이터영역으로의 복사가 수행되질 않습니다.
memcpy((char *) RAM_FUNC_AREA,(char *) RamFunc, (int)((unsigned long)EndRamFunc - (unsigned long) RamFunc));아무래도 OS에 따라 동작하는 내용이 달라질 듯한 내용인 것 같습니다.
제 테스트 환경은 WindowsXP Prof + VC++6.0 SP5 입니다.
저도 동작하지 않는군요.windows2000 server , VC
저도 동작하지 않는군요.
windows2000 server , VC++6.0 입니다.
황혼보다 어두운 자여
내 몸에 흐르는 피보다 더 붉은 자여
시간의 흐름 속에 파뭍힌 위대한 그대의 이름을 걸고 나 여기서 어둠에 맹세하노라
우리 앞을 가로막고 있는 모든 어리석은 자 들에게
나와 그대의 힘을
위대한 파멸의 힘을 보여줄 것을
흠.. 좀더 살펴보니 디버깅정보에 보여지는 함수포인터의 값과 런타임에 읽
흠.. 좀더 살펴보니 디버깅정보에 보여지는 함수포인터의 값과 런타임에 읽어오는 함수포인터의 값이 다르더군요.
그래서, 어셈블코드를 보니, 런타임에는 함수포인터를 모두 @ILT 를 통해서 접근하더군요... (ILT-Inline Table)
그러니, 복사가 제대로 안됐던 거였구요....
ILT접근을 조금 변경하면 될 것도 같긴 하네요....
14: memcpy((char *) RAM_FUNC_AREA,(char *) RamFunc, 15: (int)((unsigned long)EndRamFunc - (unsigned long) RamFunc)); 00401048 B8 0F 10 40 00 mov eax,offset @ILT+10(EndRamFunc) (0040100f) 0040104D 2D 05 10 40 00 sub eax,offset @ILT+0(RamFunc) (00401005) 00401052 50 push eax 00401053 68 05 10 40 00 push offset @ILT+0(RamFunc) (00401005) 00401058 68 48 7C 42 00 push offset RAM_FUNC_AREA (00427c48) 0040105D E8 BE 01 00 00 call memcpy (00401220) 00401062 83 C4 0C add esp,0Ch .... @ILT+0(?RamFunc@@YAHXZ): 00401005 E9 F6 00 00 00 jmp RamFunc (00401100) @ILT+5(_main): 0040100A E9 21 00 00 00 jmp main (00401030) @ILT+10(?EndRamFunc@@YAHXZ): 0040100F E9 5C 01 00 00 jmp EndRamFunc (00401170) .... --- c:\program files\html help workshop\ttt.cpp ----------------------------------------------------------------------------------------------------- 31: 32: int RamFunc() 33: { 00401100 55 push ebp 00401101 8B EC mov ebp,esp 00401103 83 EC 44 sub esp,44h 00401106 53 push ebx 00401107 56 push esi 00401108 57 push edi 00401109 8D 7D BC lea edi,[ebp-44h] 0040110C B9 11 00 00 00 mov ecx,11h 00401111 B8 CC CC CC CC mov eax,0CCCCCCCCh 00401116 F3 AB rep stos dword ptr [edi]저 내용이 쓰이는 부분
플래시 메모리에 있는 코드를 플래시 내용을 갱신시키기 위해서 사용할 경우 코드를 램으로 옮겨서 실행하는 경우가 필요한데 그러한 경우에 위의 방법처럼 사용하더군요. 임베디드 기기를 업그레이드 할 때 많이 쓰는 방식으로 알고 있는데 아마도 머신이나 OS, 컴파일러마다 방식이 다르게 나오지 않을까 하는 생각입니다.
저는 VC에서 잘 되는 걸요?제가 바꾼 것이라곤 memcpy 될
저는 VC에서 잘 되는 걸요?
제가 바꾼 것이라곤 memcpy 될 크기입니다.
그리고, 확장자는 .c 로 하여 c compiler를 사용하였습니다.
#include <stdio.h> int (*ramfunction)(); unsigned long RAM_FUNC_AREA[1000]; int RamFunc(); int EndRamFunc(); int main(int argc, char* argv[]) { memcpy((char *) RAM_FUNC_AREA,(char *) RamFunc, sizeof RAM_FUNC_AREA ); ramfunction = (int(*)())RAM_FUNC_AREA; ramfunction(); return 1; } int RamFunc() { int (*print)(const char *,...) = printf; (*print)("HI RAM AREA"); return 1; } int EndRamFunc() { #if 0 DUMMY #endif return 1; }---
http://coolengineer.com
저도 잘되는 데요...Visual C++ 6.0 & windo
저도 잘되는 데요...
Visual C++ 6.0 & window 2000 SP3
확장자는 .cpp,
#include <memory.h> #include <stdio.h> int (*ramfunction)(); unsigned long RAM_FUNC_AREA[1000]; int RamFunc(); int EndRamFunc(); int main(int argc, char* argv[]) { memcpy((char *) RAM_FUNC_AREA,(char *) RamFunc, sizeof RAM_FUNC_AREA ); //(int)((unsigned long)EndRamFunc - (unsigned long) RamFunc)); // 이렇게 하니까 안되네요.. ramfunction = (int(*)())(void *)RAM_FUNC_AREA; ramfunction(); return 1; } int RamFunc() { int (*print)(const char *,...) = printf; (*print)("HI RAM AREA\n"); return 1; } int EndRamFunc() { #if 0 DUMMY #endif return 1; }로 했습니다.
코드 메모리의 영역을 결정하는 부분에서 문제였군요.감사 합니다.
코드 메모리의 영역을 결정하는 부분에서 문제였군요.
감사 합니다.
황혼보다 어두운 자여
내 몸에 흐르는 피보다 더 붉은 자여
시간의 흐름 속에 파뭍힌 위대한 그대의 이름을 걸고 나 여기서 어둠에 맹세하노라
우리 앞을 가로막고 있는 모든 어리석은 자 들에게
나와 그대의 힘을
위대한 파멸의 힘을 보여줄 것을
댓글 달기