티스토리 뷰

 

아래는 원본 소스입니다.


하다보니 바귄게 많은데, 아래 캡처한 어셈블리와는 조금 다를 수 있습니다.

static void Main(string[] args)
{
    int num = 69905;
    char strOK = (char)num;
    object oo = num;
    object oo2 = oo;
 
    int num3 = 5;
    num = num3;
 
    string str1 = "ca";
    str1 = oo as string;
 
    Nullable<int> num2 = (str1 as objectas Nullable<int>;
 
    string str3 = str1;
    string str2 = str1 + str3;
 
    int numOK = (int)oo;            
    char strFail = (char)oo;
    
    Console.Read();
}
 

 

int를 char에 넣을 때 어떻게 작동할까요?

ebp-40h가 가리키는 메모리 값은 아래와 같습니다.

 

아래는 int num의 값이 char로 강제로 넣을 때, 보이는 모습니다. char는 2바이트이므로, int의 4바이트를 다 받지 못해서 아래와 같이 값이 입력됩니다.

(생략)B4가 char

(생략)B8이 int 입니다.

 

그다음…

(보기 편하기 위해 num에 1을 넣었습니다.)

 

아래와 같이 값을 따라가 본다.

역시 1이 들어가 있네요.

 

해당 프로시저를 보면

해석하면 다음과 같다

대략 이렇습니다.

 

코드를 좀 더 뜯어 봅니다.

62A94AA8h는 뭘까요?

(다시 재 컴파일)

call 132100이 힙에 메모리를 할당하는 것으로 보입니다.

재 컴파일 해도, 62A93AA8h라는 값은 그대로 인데요, 아마 이 값이 ecx에 해당 타입의 정보를 저장하는 것으로 생각합니다. 저 값이 이후에, 값 변환시 체크를 하여 잘못된 값이 들어가면 에러를 내도록 합니다. 현재 저 값은 int형 object 임을 알려주는 값으로 보입니다.

보면 열심히 복사 덕질을 하는데요,

132100 프로시저를 호출한 후에, eax에 할당된 메모리 주소가 생겨납니다.

확인ㅎㅎ

 

확인 결과…

프로그램을 다시 켜서, 위의 eax값과 다른 값임을 염두해주세요..

일부러 꼼수를 부려 object를 3개 할당해보았습니다. object는 12byte를 만드는 것 같습니다. 그냥 똑같이 3개가 만들어 졌네요. 이 값에 저장되는 걸 좀 볼가요?

 

요로케 저장.

해당 명령어를 지나면서, 할당된 메모리 위치를 저장합니다.

 

이 또한 주소를 저장하는데요,

object 참조 주소가 저장되었습니다.

아래것이 oo 이고, 위의 것이 oo2입니다. 서로 참조하는 위치가 같네요.

 

요 값도…

이렇게 할당.

 

이제 봅시다..

해당 코드를 넣으면, str1에 object가 들어가지 않고, null이 입력됩니다.

처음부터.. cmp로 분석하는데, 이것이 맞으면 바로 213102 번지로 건너가서 실행이 됩니다. 213102 명령이, oo의 주소를 str1으로 복사해서 붙이도록 말하고 있습니다. 그런데 ebp-48h이 가리키는 값이 0이 아니라서.. je를 무시하고 2130EE로 넘어갑니다. 002130F1에서 ebp-48h의 값이 62A9224C와 동일한지 묻습니다. 쓰다보니 생각난거,,, 지금 막 어셈을 뜯어서 이야기하는거라 전혀 이해가 안될텐데(…)

가장 빠른 경우,

다른 경우 요로케 지나간다.. (프로그램을 다시 껐다켜서 주소가 달라졌다… ㅎ)

다른 경우이므로, 정상적인 값이 입력되지 않아 str1은 null 이다.

따라서 아래에 억측스럽게 string을 int로 넣기위한 뻘짓(…)은 당연히 null이 들어간다.

 

null 이다 ㅎ

 

하지만 뻘짓 하면 num2에다가 값을 넣을 수 있다(…) 이게 디버깅의 맛이랄까..(…)

위와 같이 실행주소를 바꿔주어서 강제로 str1에다가 oo의 주소를 넣어버릴 수 있다.

강제로 입력한 것이 아니라.. str1이 int로 만들어진 object를 참조하도록 되어버렸다.. 뭐 지금 과정에서 소스가 수정된 거는 지나치도록 하자.. 사소하니까 !!!

 

요로케 값이 잘 들어가는 것을 볼 수 있습니다… 원래는 보호하는 코드가 들어있어서 안되는데, 제가 강제로 str1을 int형 object(이렇게 부르면 되나?)로 변환시켜버렸기에, 들어갈 수 있게 되어버린 겁니다. 네 그러면…

 

이제 이 코드는 어쩔까요(…)

디스어셈블리가 된 걸 보면 아시겠지만… 다른 형 변환 소스와 달리 보호해주는 코드가 없습니다. 왜냐면 컴파일이 판단하기에 둘 다 string 이니까, 형 변환을 보호할 필요가 없겠지요! 그래서 빼버린 것이지만… 제가 임의로 str1을 int형 object로 바꾸었기에.. 이제 기상천외한 사건이 발생할겁니다. 과연 69905는 무엇을 가리킬까요(…)

뻔한 힌트를 주자면 69905 주소에서 값을 마구 불러들이겠죠.

저 에러는 어디서 내는 걸가요…?

해당 프로시저를 통해 냅니다.. 그럼 이녀석은?

즐거웁게 길게..

그냥 해석을 포기했습니다.. 실은 별로 궁금한 것도 아니라(…)

아무튼 여기서 이래저래 가져온 값으로 string이라 생각하며 작업하겠지만…

 

급, string의 구조가 궁금해서 봤는데..

위 아래로 2개를 선언했구요.

위에는 string str1 = "c";

아래는 string str2 = "ca"; 입니다.

이걸로 보건데, 파란 네모칸이 string 값의 길이를 나타내는 것 같구요, 아마 char배열로 구성되기에 2바이트를 사용하는 것으로 보입니다.

 

다시 돌아와서..

int형 object인 oo의 경우, 위와 같은 코드를 통해 값이 바로 들어가집니다.

 

이거는…

call 6377EA9A 에서 에러를 냅니다.

하지만 그냥 살포시 넘겨버리면..

네.. 정말 쓸모 없는 짓을 하였습니다(…)

아무튼 보니까, 컴파일러가 안전한 형 변환 코드를 넣어주기도 하지만, 프로시저에서 검사를 다시금 하는 모양입니다.

 

마지막으로,, 박싱 관련..

object oo = num 을 보시면…

확실히 박싱할 때, 코드가 더욱 길게 만들어지네요.

 

바로 쓰면 이렇게 짧은데 말이죠.

 

결론 : …이걸 왜 한걸까…