$ cat tiny_shell.s
BITS 32
global _start

_start:
;int execve(const char * filename, char * const argv[], char * const envp[])
; execve("/bin//sh", ["/bin//sh", 0x0], [ 0x0 ]);

xor eax, eax  ; eax = 0
push eax
push '//sh'
push '/bin'   ; "/bin//sh", 0x0

mov ebx, esp  ; const char * filename = "/bin//sh", 0x0
push eax
mov edx, esp  ; char * const envp[] = [ 0 ]
push ebx
mov ecx, esp  ; char * const argv[] = [ "/bin//sh", 0 ]
mov al, 11
int 0x80

$ ndisasm -B32 tiny_shell
00000000  31C0              xor eax,eax
00000002  50                push eax
00000003  682F2F7368        push dword 0x68732f2f
00000008  682F62696E        push dword 0x6e69622f
0000000D  89E3              mov ebx,esp
0000000F  50                push eax
00000010  89E2              mov edx,esp
00000012  53                push ebx
00000013  89E1              mov ecx,esp
00000015  B00B              mov al,0xb
00000017  CD80              int 0x80

$ xxd tiny_shell
0000000: 31c0 5068 2f2f 7368 682f 6269 6e89 e350  1.Ph//shh/bin..P
0000010: 89e2 5389 e1b0 0bcd 80                   ..S......


find /-user root -perm -4000

위의 것은 root로 setuid가 걸린 파일들을 찾아준다.

여기서 에러가 화면에 출력되어 짜증나는데 에러가 나오지않게 할려면

끝에 2> /dev/null 를 추가하면된다.


find /-user root -perm -4000 2> /dev/null
Server
 * recv_n에 10초간 타임아웃을 주고 대기함
        char    buff[1024];
        size_t  recvLen = 0;
        ACE_Time_Value  timeout(10);
        int ret = peer.recv_n( buff, sizeof(buff)-1, &timeout, &recvLen );
        ACE_DEBUG( (LM_DEBUG,
                ACE_TEXT("ret[%d] recvLen[%d] : [%.*C]\n"),
                ret, recvLen, recvLen, buff) );
Client
 * 접속하자 마자 첫 메세지("Hello ")를 보내고(send_n)
 * 5초후 (sleep 5초) 나머지 데이터("World!")를 보내고 접속을 끊는다.
        peer.send_n( "Hello ", 6 );

        ACE_OS::sleep( 5 );
        peer.send_n( "World!" , 6 );
        peer.close();
 * 결과 :
 *  recv_n는 첫 메세지를 받고 timeout(10초)동안 블럭이 걸려있었으며
 *  5초후 나머지 데이터를 받고 0을 반환후에 종료하였습니다.
 *  받은 데이터 사이즈는 recv_n 4번째 인자로 받습니다.
$ ./recv
ret[0] recvLen[12] : [Hello World!]
서버 소스 Recv.C
/*
 * 10초간 recv를 걸어놓고 받는것을 테스트함.
 *
 * 상대방에서는(send.C) 접속하자 마자 첫 메세지를 보내고
 * 5초간 sleep를 준다음 나머지 데이터를 보내고 접속을 끊는다.
 *
 * 결과 :
 *  recv_n는 첫 메세지를 받고 timeout(10초)동안 블럭이 걸려있었으며
 *  5초후 나머지 데이터를 받고 0을 반환후에 종료하였습니다.
 *  받은 데이터 사이즈는 recv_n 4번째 인자로 받습니다.
 */
#include <ace/SOCK_Stream.h>
#include <ace/INET_Addr.h>
#include <ace/SOCK_Acceptor.h>
#include <ace/Time_Value.h>
#include <ace/Log_Msg.h>

int ACE_TMAIN( int, ACE_TCHAR * [] )
{
        ACE_INET_Addr   myaddr(9090);

        ACE_SOCK_Acceptor       acceptor;

        if( acceptor.open( myaddr ) == -1 )
        {
                ACE_ERROR_RETURN( (LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("acceptor.open()")), 1 );
        }

        ACE_OS::sleep(5);
        ACE_SOCK_Stream peer;
        if( acceptor.accept( peer ) == -1 )
        {
                ACE_ERROR_RETURN( (LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("acceptor.accept()")), 1 );
        }

        char    buff[1024];
        size_t  recvLen = 0;
        ACE_Time_Value  timeout(10);
        int ret = peer.recv_n( buff, sizeof(buff)-1, &timeout, &recvLen );
        if( ret == -1 )
        {
                ACE_ERROR_RETURN( (LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("recv_n()")), 1 );
        }

        ACE_DEBUG( (LM_DEBUG, ACE_TEXT("ret[%d] recvLen[%d] : [%.*C]\n"), ret, recvLen, recvLen, buff) );
        peer.close();

        return 0;
}
클라이언트 소스
send.C
/*
 * 서버에 접속하자 마자 첫 메세지("Hello ")를 보내고
 * 5초간 sleep를 준다음 나머지 데이터( "World!\n")를 보내고 접속을 끊는다.
 */

#include <ace/SOCK_Stream.h>
#include <ace/INET_Addr.h>
#include <ace/SOCK_Connector.h>
#include <ace/Time_Value.h>
#include <ace/Log_Msg.h>
#include <ace/OS.h>

int ACE_TMAIN( int, ACE_TCHAR * [] )
{
        ACE_INET_Addr   svrAddr(9090, ACE_TEXT("127.0.0.1"));

        ACE_SOCK_Connector      conn;

        ACE_SOCK_Stream peer;
        if( conn.connect( peer, svrAddr ) == -1 )
        {
                ACE_ERROR_RETURN( (LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("connect()")), 1 );
        }

        char    buff[1024];
        ACE_OS::strcpy( buff, "Hello " );
        if( peer.send_n( buff, ACE_OS::strlen(buff) ) == -1 )
        {
                ACE_ERROR_RETURN( (LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("send_n() 2")), 1 );
        }

        ACE_OS::sleep( 5 );
        ACE_OS::strcpy( buff, "World!" );
        if( peer.send_n( buff, ACE_OS::strlen(buff) ) == -1 )
        {
                ACE_ERROR_RETURN( (LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("send_n() 1")), 1 );
        }

        peer.close();

        return 0;
}

결과
$ ./recv
ret[0] recvLen[12] : [Hello World!]
서버가 죽는 현상이 발생하였고
SIGPIPE, 혹은 Broken pipie. 메세지가 나온다면

이미 닫힌 소켓에 데이터를 보내기를 했을것이다.

SIGPIPE를 검색해 보면 알겠지만 파이프가 끊겼을 경우 발생하는 signal이다.
아래 참고 사이트를 보면 알것이다.

만약에 SIGPIPE를 받아도 죽지않고 그대로 진행하게 할려면 해당 시그널을 무시해보리는 방법이 있다.
무시하는 방법은

고전적인 signal 함수 사용
signal(SIGPIPE, SIG_IGN);    // sigpipe 무시.

sigaction을 사용
struct sigaction act;
act.sa_handler = SIG_IGN;
sigemptyset( &act.sa_mask );
act.sa_flags = 0;
sigaction( SIGPIPE, &act, NULL );

ACE 프레임 워크를 사용한다면
ACE_Sig_Action sig_act (SIG_IGN); 
sig_act.register_action (SIGPIPE);

를 하면된다.

만약 send를 한후에 SIGPIPE에러를 인지 확인할려면
errno 값이 EPIPE 값인지 확인하면된다

참고 사이트
http://kelp.or.kr/korweblog/stories.php?story=02/03/13/6152214
http://blog.naver.com/PostView.nhn?blogId=hyungii&logNo=130081645365

* GetTickCount는 시스템이 시작되고 나서의 시간을 밀리 초로 반환하는 함수입니다.

* GetTickCount는 시스템이 시작되고 나서 49.7일이 지나면 0에서 다시 시작합니다.

 * GetTickCount가 오버플로우되어 0으로 값이 설정되었더라도 예전값과 - 연산을 해도 크게 지장은 없습니다.
  DWORD 형이 부호가 없기 때문에  현재값 - 예전값 은 49.7일 이전 값이 아니면 옳은 값을 반환합니다.

** 0x00000001 - 0x00000000 = 1
** 0x00000000 - 0xFFFFFFFF = 0x00000000 + (0xFFFFFFFF 2의보수) = 0x00000000 + (0x00000001) = 1


 간단하게 4bit 로 계산을 해보겠습니다.

4bit의 최대값은
1111 (2진수) == 15(10진수)

4bit의 최소값은
0000 (2진수) == 0(10진수)

최소값 - 최대값 을 계산해보면
1111의 2의 보수값은
1111의 역수 0000 더하기 1 = 0001

2진수) 0000 - 1111 = 0000 + 0001 = 0001
10진수) 0 - 15 = 0 + 1 = 1

따라서 값은 1이 나온다.

마찬가지로 5 - 15(4비트 최대값)는 6이 된다.
0101 - 1111 = 0101 + 0001 = 0110(6)

14 - 15 = 15
14 - 15(4비트 최대값) = 1110 - 1111 = 1110 + 0001 = 1111(15)


ACE를 공부하면서 해당 책을 4, 5번째 읽는중입니다.

한번씩 더 볼때마다 머리속에 좀더 와닫는 느낌을 받고 있는데요^^.

그런데 왠지 프로그램 공부법이 많이 잘못되지 않았나 하는 생각을 가지게 됩니다.

해당책은 5번정도 봤는데.. 책에 있는 내용을 보고 따라서 코딩은 1회정도밖에 안했다는겁니다.

그래서인지 잘 이해를 못하는 느낌을 받습니다.

몇몇 구간은 작은 프로젝트 때문에 여러번 보고 코딩하고 확인하고 수정하고 해서
어렵지 않게 배우게 되었습니다만..

그외에는 아직이해가 부족하거나 어렵게 생각되게 되는점이 있습니다.

그래서 인데 프로그램을 이해하는데 가장좋은방법은(일단 저에게..) 책을 보고 그것을 그대로 코딩해보고 컴파일및 실행을 꼭 해보는것이라고 생각합니다.
	// 디렉토리인지 알아냄.
	bool is_directory( const std::string & path )
	{
		DWORD ret = ::GetFileAttributes( path.c_str() );

		if( ret == INVALID_FILE_ATTRIBUTES )
			return false;

		if( ret & FILE_ATTRIBUTE_DIRECTORY )
			return true;

		return false;
	}

	// 파일 경로와 관계된 모든 부모 디렉토리를 만든다.
	bool dig_path( const std::string & fullPath )
	{
		using std::string;
		string  path = fullPath;

		// 파일경로에서 디렉토리 경로만 얻음.
		string::size_type pos = path.find_last_of( "/\\" );
		if( pos != string::npos )
		{
			path.erase( ++pos, string::npos );
		}

		// 네트워크 경로 인가? 예제) "\\192.168.0.1\test"
		pos = 0;
		if( path.compare( 0, 2, "\\\\") == 0 )
			pos = 2;

		// 상위 경로를 찾아가며 디렉토리를 순서대로 만든다.
		while( (pos = path.find_first_of( "/\\", pos )) != string::npos )
		{
			string subPath = path.substr( 0, pos++ );

			if(is_directory(subPath )==false)
				::CreateDirectory (subPath.c_str(), 0);
		}

		return true;
	}
http://studiostyl.es/schemes

여기 visual c++ 버전별 여러가지 스타일이 있다.

도구 --> 설정 가져오기및 내보내기 메뉴로 가서 설정을 적용해보자.




ACE_OutputCDR를 사용하는데 Big endian 저장이되지 않는 현상을 발견했습니다. 아무리 옵션을 바꿔봐도 되지않아 찾아보니... ACE 컴파일을 다시 해야하더군요.
$ACE_ROOT/ace/config.h 파일에 아래 내용을 추가한후 재컴파일하여 빌드하세요.
#define	ACE_ENABLE_SWAP_ON_WRITE	1	// enable swap byte_order
테스트 코드

#include "ace/cdr_stream.h" #include "ace/log_msg.h" void OutputCDR_Test( ACE_CDR::UShort id, int endian ) { ACE_OutputCDR cdr( sizeof( id ), endian ); cdr << id; ACE_HEX_DUMP( ( LM_DEBUG, cdr.begin()->rd_ptr(), cdr.begin()->length() ) ); } int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) { ACE_DEBUG( ( LM_DEBUG, ACE_TEXT("\nBYTE_ORDER_LITTLE_ENDIAN\n") ) ); OutputCDR_Test( 0x1234, ACE_CDR::BYTE_ORDER_LITTLE_ENDIAN ); ACE_DEBUG( ( LM_DEBUG, ACE_TEXT("\nBYTE_ORDER_BIG_ENDIAN\n") ) ); OutputCDR_Test( 0x1234, ACE_CDR::BYTE_ORDER_BIG_ENDIAN ); return 0; }
결과값
BYTE_ORDER_LITTLE_ENDIAN
HEXDUMP 2 bytes
34 12                                              4.

BYTE_ORDER_BIG_ENDIAN
HEXDUMP 2 bytes
12 34                                              .4
ACE 기반 채팅 서버(Proactor)와 MFC기반 채팅 클라이언트입니다.

이 채팅 프로그램은  

TCP/IP 소켓 프로그래/

한빛미디어

책을 참고 하였음을 알려드립니다

클라이언트 부분은 버그 몇개(심각한 버그 포함)를 수정하여 책을 보고 작성및 소스를 참고 하였으며

서버 부분은 책과는 다르게 프로토콜을 제외한 모든 부분을 새로 작성하였으며
ACE Reactor 기반을 거처 Proactor 기반으로 변경하여 만들었습니다.

실행방법은 압축을 풀면 bin디렉토리에 ACE_ChatServer.exe를 실행시키고
ChatClient.exe 를 실행시키면됩니다.

사용포트는 9090 포트를 이용합니다.


플로우 차트와 설계 문서는 아래를 참고 하세요.

ACE 기반 채팅서버 - 서버 접속

ACE기반 채팅서버 - 대화방생성

ACE 기반 채팅서버 - 대화방 입장

채팅서버 - 대화

채팅서버 - 클라이언트 접속 종료

대기방



대화방



서버



소스및 실행파일

+ Recent posts