오늘 열심히 툴을 만들다가 또 쓰레드 때메 지난 번이랑 똑같은 문제로 고생하는 거도 피곤하고- 하나밖에 못넘겨주는 파라미터로 다이얼로그를 넘겨도 UpdateData도 안되고 여기저기 걸리는게 많아서 고생ㅠ (지난번에 고생해서 알아냈다시피 쓰레드 내에서는 윈도우(UI쪽)를 건드리지 않는 것이 상책이다.) 그래서 이승희 주임님한테 물어봤다 -_- (창환이 말로는 Windows UI 프로그래밍 쪽으로 일가견이 있으시다고)
UI와 내부 연산을 분리할 것 UI 관련 부분 (윈도우로부터 데이터를 받아오거나 출력하거나, 윈도우 상태를 변경하는 부분) 들이 쓰레드 안에 들어가서 파일을 옮기고 프로세스를 실행하는 등의 실제 연산 중간중간에 박혀있다. 작업 쓰레드 내에서 UI 관련 연산을 하는 건 안좋은 습관.
초기화를 비롯한 실행 조건 처리는 첫부분에서 한꺼번에 할 것 파일을 복사할 경로를 확인하고 파일 복사, V3 경로 확인하고 실행. 이런 식으로 그 때 그 때 확인하는 것보다는 실행하는데 필요한 모든 조건을 확인한 후에 작업을 시작하도록.
예외처리 이 코드에서는 안나타나지만 파일 이동에 대해서 예외처리를 제대로 해주지 않았다. 어떤 이유에서든 연산이 실패할 가능성이 있으면 예외처리 루틴으로 가도록-
------------------
사실 저 모든게 쓰레드를 제대로 사용할 줄 몰라서 그런거다 -_- 저 연산들이 순차적으로 실행되어야하는 연산이기 때문에 WaitForSingleObject 를 써서 기다려야되는데 Thread의 경우는 WaitForSingleObject의 파라메터로 CThread 포인터를 바로 넘기는게 아니라 CThread->m_hThread를 넘겨줘야 한단다.
전에 한번 WaitForSingleObject 써봤는데 쓰레드만 생성하고 바로 돌아와서 메인쓰레드랑 동시에 실행되는 바람에 순차적 실행이 안됐던 적이 있었는데 핸들값을 잘못 넘겨줬기 때문이었나보다.
여튼 그래서 순차적으로 실행되도록 하려고 쓰레드에 다 밀어넣고 했는데 이러면 안된다고 하시는군. Cleaner.MoveSample(), V3.Run(), Cleaner.RemoveEmptyFolder() 만 각각 쓰레드를 생성하여 실행하는 것이 좋다고 한다.
void CMoveDlg::OnOK() { // TODO: Add extra validation here GetDlgItem(IDOK)->EnableWindow(false); GetDlgItem(IDC_STATIC_STATUS)->SetWindowText(" 샘플 복사 중");
// V3 검사 수행 GetDlgItem(IDC_STATIC_STATUS)->SetWindowText(" V3 실행 중 - 종료하지마세요"); //sprintf(tgtpath, "%s%04d%02d", tgtpath, m_year, m_month); // 경로 설정 CExcuteProgram *pV3 = new CExcuteProgram("V3", programpath, tgtpath);
// 바이러스 검사 쓰레스 실행 -> 리턴값 확인 pThread = AfxBeginThread(V3RunThread, (LPVOID)pV3); if( pThread != NULL){ // 검사 종료 윈도우를 찾아서 닫아주는 쓰레드 실행 AfxBeginThread(CloseV3WindowThread, pThread); WaitForSingleObject(pThread->m_hThread, INFINITE); } else{ GetDlgItem(IDC_STATIC_STATUS)->SetWindowText("쓰레드를 생성할 수 없습니다"); GetDlgItem(IDOK)->EnableWindow(TRUE); return; }
GetDlgItem(IDC_STATIC_STATUS)->SetWindowText(" 빈 폴더 삭제 중");
Working Thread와 UI Thread를 분리해야한다는 말은 많이 들었지만 어떻게 해야하는지 잘 몰랐는데 대충 이렇게 하는건가;; 조금 깔끔해 진것 같긴 하지만 어설프다. 그래도 그럭저럭 필요한 기능은 전부 구현이 되서 만족 ^^ 한가지 아쉬운거라면 저 쓰레드 함수들.. Dialog 밑에 주렁주렁 달려있어서 좀 이상하다는거. 좀 더 깔끔하게 정리된 코드를 짜고 싶다. 디자인 패턴을 공부해야지!
-------------------- 굉장히 부끄러운 일이지만 회사에서 코딩을 하다보면 정직원분들이 상식이라고 생각하는 부분을 나는 잘 모르고 있는 경우가 많아서 정직원들이 내 코드를 보면 왜 이런식으로 짰을까- 라고 놀람을 떠나 어이없어하는 경우가 있다 -_- (변수명이라거나 예외처리라거나 하는 기본적인 부분부터 프로그램의 구조같은 것까지 여러가지 면에서)
정말이지 코딩같은건 어디서 체계적으로 배우는게 아니라서 (공이라고 해도 뭔가 체계를 가지고 배운 적은 없다. 이상한 일이긴 하지만) 참 힘들다. 지식도 지식이지만 코딩 습관 또한 중요한 부분을 차지하는 듯하다.
Moves an existing file or a directory, including its children. To specify how to move the file, use the MoveFileEx or MoveFileWithProgress function. To perform this operation as a transacted operation, use the MoveFileTransacted function.
Parameters lpExistingFileName [in] The current name of the file or directory on the local computer. In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "//?/" to the path. For more information, see Naming a File. Windows Me/98/95: This string must not exceed MAX_PATH characters.
lpNewFileName [in] The new name for the file or directory. The new name must not already exist. A new file may be on a different file system or drive. A new directory must be on the same drive. In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "file://?/" to the path. For more information, see Naming a File. Windows Me/98/95: This string must not exceed MAX_PATH characters.
Return Value If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError.
Remarks The MoveFile function will move (rename) either a file or a directory (including its children) either in the same directory or across directories. The one caveat is that the MoveFile function will fail on directory moves when the destination is on a different volume.
If a file is moved across volumes, MoveFile does not move the security descriptor with the file. The file will be assigned the default security descriptor in the destination directory.
The MoveFile function coordinates its operation with the link tracking service, so link sources can be tracked as they are moved.
----------- including its children
이것도 모르고 재귀 호출하면서 경로 탐색해서 CopyFile 로 하나하나 폴더 만들고 하위 파일 복사하고 빈 폴더 지워주고 ㅠ-ㅠ
난 실행압축을 끝까지 못풀고, 드랍하는 파일을 수집을 못해서 완전히 분석을 못했는데. 정진성 주임님이 달아주신 코멘트
철우군 보세요. ~
- msgr.dll 은 C:\WINDOWS\Downloaded Program Files 에 설치가 됩니다. (여기는 액티브 엑스가 설치 되는 곳이죠.)
- 해당 폴더내 파일(%windir%\Downloaderd Program Files)은 탐색기에서는 보여지지 않습니다. 다른 파일 관리자를 써보세요. TC 같은 거..
- msgr.dll 은 Win-Trojan/Downloader.9728.CO 로 기진단 되네요. ; ) - 실행압축 해제는.... 올리에서 아래 0040B098 에 BP 걸고 shift+F9 (Pass exceoption to standard handler and run)로 달리세요.
pushad 해서 레지스트리 값 백업한 다음에 popad 해서 복구한후에 실제 프로그램 시작점으로 jmp 알고 있는 패턴인데도 잘 안보인다
디버거로 따라갈 때는 항상 어느 선까지 쫒아들어갈껀가 고민하는게 너무 힘들다. 너무 세부적인거까지 따라가봤자 결국은 나한테는 별 의미없는 연산, 혹은 시스템내에서 사용하는 콜 그렇다고 안따라가기에는 그 안에 뭐가 숨어있을 지 알 수 없어서 계속 보게되고 보다보면 어느새 미궁- 여기는 어디인가 ㅠ_-
여튼 또 하나 배웠습니다. 친절한 피드백에 감사 ^^
-------------- 방금 가르쳐주신대로 풀어봤는데 잘 된다. 그리고 내가 어제 팩을 못푼건 아니었다. 풀고보니 내가 어제 따라갔던데랑 똑같네. 이 방법이 훨씬 쉽긴 하지만..shift+f9 라는 방법이 있다니 ㅋ (난 pushad에 레지스트리값이 저장되는 곳에 하드웨어 bp를 걸고 반복해서 따라가는 방법으로 풀었다)
풀고난 후의 코드를 이해못했던건데. Naked Packer V1.0 으로 실행압축되있는 이 코드- 상당히 독특하다.
압축을 풀고보면 push와 jmp의 나열. 대체 어디서 함수를 호출하고 어떤 루틴을 타는건가 모르겠다-_-; 그 jmp를 따라가면 또 무지하게 긴 jmp로 둘러싸인 루프가 나와서 뭔가 했었는데
스택에 어떤 값을 push 한 담에 jmp 로 어딘가로 뛴다. 거기서 무지하게 긴 루프를 도는 과정에서 자기가 호출하고자 하는 api의 메모리상의 주소를 얻어서 해당 api의 파라미터와 함께 스택에 push 해둔다.
마지막에 호출하고 싶은 api 시작주소로 return하면 그때 스택에 남아있던 값이 그 api의 파라미터가 되어 해당 api가 호출된다.
루프를 마지막으로 탈출하는 지점에 bp를 걸고보니 위와 같은 방식으로 api를 호출하는 거였다.
case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: break; } return TRUE; }
어제 운연이가 갑자기 물어봤던 키보드 메세지 후킹과 dll 인젝션- 하도 많이 듣고 자주 보던 것들이지만 막상 구현해놓은 소스를 보니까 없고 해서 어떤 식으로 하는지에 대해 관련 기법이랑 문서만 알려주고 말았는데 오늘 회사에서 전에 공부하던걸 찾아봤다. 구체적인 방법도 알고있는 거랑 해보는 거랑은 좀 다른 것 같다.
막연히 알고 있는데서 그치지 말고 실제로 내가 할 수 있는 나의 스킬로 만들어야겟다. 그래야 필요할 때 써먹지 ㅋ
전까지는 이선임님이 할당해준 악성코드 샘플을 한개씩 받아서 분석한 다음에 결과를 메일로 보내는식으로 했는데 본격적으로 샘플을 분석하는 일을 인턴의 업무로 정착시키기 위해서인지, 그리고 어느 정도 트레이닝이 되서인지 다른 직원분들에게도 참조 메일을 보내기로 했었던 그 첫날! (이선임님이 다른 직원들의 피드백을 통해서 더 많이 배울 수 있을꺼라고 그러셨다.)
대망의 삽질 -0- dll 파일이었는데 아무리 올리디버거에서 로딩을 하려해도 당췌 로딩이 안되서 읽을 수 조차 없는거다. 그래서 파일이 깨진 줄 알고 열심히 헤더도 뜯어보고 팩정보도 찾아보고 (UPack이었음) 동일한 종류의 다른 팩과도 비교해보고 그랬는데 도무지 모르겟어서 그냥 깨진 파일이라고 실행 안된다고 내보냈는데..
바로 고흥환선임님한테서(내가 속해있는 보수적인 C조ㅋ 의 조장이심;; ) 실행되는 파일이라고 게임핵으로 진단추가 하라고 메일이 왔다 ㄷㄷㄷ
아 쪽팔려.. 더구나 고선임님은 인턴에게 샘플분석 시키지 말고 인턴 숫자를 줄이자는 쪽의 대장-_-; 우리 인턴들과는 별로 말도 안하시고 그래서 평소에도 좀 거리감도 느끼고 그랬는데 바로 저렇게 날아오니까 진짜 난감하고 쪽팔렸다. 내 딴에는 이리저리 알아보고 안되서 그랬는데 바로 그렇게 메일 와서 기분도 좀 나빴고 자존심도 상했다.
젠장- 공부 많이 해서 잘하게 되고 말테다 -_- 근데 이놈의 샘플 분석은 메뉴얼 같은 것도 없고 경험과 감, OS와 파일구조, API에 대한 전반적인 지식으로 맨땅에 헤딩하듯이 배워야 하는 거라.. 힘들다.
이번 신입사원 분들도 실수도 많이 하고 그래서 다른 정직원들이 가르쳐주고 그러더만 인턴들은 기간도 짧고 배워봐야 오래 못써먹어서인지 업무에 부담느껴가면서 가르쳐주지 않으려는 분위기. 게다가 이번 주는 우리조가 긴급조라 딱히 물어볼 사람도 없다. 다들 일이 바빠서.. 안바빠도 크게 잘 가르쳐주진 않더라만 ㅋ 여튼 어제 실수해서 난감했다.
로딩이 안된 이유 ================= PE파일의 경우에 헤더에 파일의 종류(dll인지 exe 인지)를 나타내는 플래그가 있어서 디버거에서 로드할 때 알아서 해준다. 그렇지만 올리에서 로드할 때 간혹 확장자가 없으면 dll로 인식하여 olly loader 실행되지만 읽을 수 없는 경우가 발생한다. 경험부족 경험부족 ㅠ
DLL 분석법 ================= dll의 경우 다른 프로세스에 인젝션되어 실행된다. 크게 두가지로 나누어 로딩된 후에 expot하는 함수가 있는 경우와 없는 경우가 있다.
1. expot 함수가 없는 경우 dll 메인에서 수행하는 루틴만 따라가보면 뭐하는지 대충 알 수 있다. 대부분 스레드를 만들어서 수행되는 경우가 많으므로 스레드를 하나하나 확인해볼 것. olly loader 에서 생성한 스레드가 아니어서인지 따라가 보는게 힘들다.
EIP를 강제로 옮기는 경우에 파라메터나 레지스터 상태가 다르고, 조건이 달라서 악의적 루틴으로 분기하지 못하는 수도 있으므로 유의해야한다. 대부분 iexplorer.exe, winlogon.exe 등 특정 프로세스에 붙어서 자기를 로딩한 프로세스를 확인한 후에 실행되는데 이러한 루틴들을 잘 확인해 볼 것. 나머지는 exe 파일과 동일~
2. export 함수가 있는 경우 dllmain에서 하는 작업들을 잘 살펴보고- 익스포트 함수가 있으므로 메인에서는 별 거 안할 수도 있다- 그 후에 중요한 것이 어떤 export 함수를 제공하는가. 한번 따라가 보는 것.
olly 에서 call exported funcion 인가 하는 기능을 제공해서 export 함수를 호출해 볼 수 있다. (최근에 발견한 사실 ㅋ)
export 함수의 위치에 브레이크 포인트를 걸고 콜해주면 거기로 EIP가 이동. 뭘 하는지 따라가 볼 수 있다. 단 이 경우에도 파라미터를 정확히 넘겨주지 못하므로 이 점에 유의하여 트래킹-