'Perl'에 해당되는 글 63건

  1. 2012.10.24 [KPW2012] Notepad Letter (7)
  2. 2012.10.11 [KPW2012] Korean Perl Workshop 2012 - 초대합니다 :)
  3. 2012.04.12 8. Registry File Parser Source code (6)
  4. 2012.04.06 4. NK Record
  5. 2012.04.04 2. Registry hive structure (1)
  6. 2010.12.01 2010 Korea Perl Advent Calendar (2)
  7. 2010.11.10 perl URI::Escape 모듈 (3)
  8. 2010.09.13 Naver Perl 카페회원 1000명을 돌파! (10)
  9. 2010.07.30 드디어 "Perl 6"이 출시 되었습니다 :) (3)
  10. 2010.06.16 소스 다이어트의 적절한 예 (3)

Naver Perl Community & Study Cafe


2012.10.24 03:37

[KPW2012] Notepad Letter

2008년말 쯤에 한글 문자열을 자판에 입력되는 영문으로 바꾸는 방법  이라는 글을 쓴적이 있습니다.

당시에는 별 생각없이 기술연구 목적으로 테스트 용으로 만들었는데...

가끔 이 모듈을 이용해서 응용작품을 만들어 봐야 겠다는 생각을 하곤 했었죠.


최근에는 인문학이나, 감성, Design for humans 등등 

사람 중심의 문화가 많이 생기고 정착되고 있는 시기입니다.


이렇듯 소프트웨어를 통해 사람의 마음을 움직이는 프로그램이 필요하다고 느꼈고, 

향후에는 사람에게 메세지를 전달하는 정성을 넣어 감동으로 연결시키는

인간적인 프로그램이 앞으로는 크게 이슈가 될 것 같더라구요 ㅋㅋ


그런면에서 Notepad Letter은 그런 부분을 충족시켜주는 부분이 많았습니다.


4년만에 다시 열린 Korean Perl Workshop 2012 에서 발표할 기회가 생겨,

이 모듈을 다시 한번 연구해서 살을 붙여보자 하고 결심했습니다.


아래는 KPW2012 발표 자료입니다.

https://docs.google.com/file/d/0B3NurlLan8deZUJ4Yk1jVy1aM3c/edit?pli=1


Hangle.pm

package Hangle; use strict; use warnings; use Lingua::KO::Hangul::Util qw(:all); use base qw/Exporter/; use Encode qw/decode encode/; our @EXPORT_OK = qw/transformation/; sub transformation{ my $arg = shift; my $str = decode('cp-949', $arg); binmode STDOUT, ':encoding(cp-949)'; my %hangle = ( #초성 "\x{1100}" => 'r', "\x{1102}" => 's', "\x{1103}" => 'e', "\x{1105}" => 'f', # ㄱㄴㄷㄹ "\x{1106}" => 'a', "\x{1107}" => 'q', "\x{1109}" => 't', "\x{110B}" => 'd', # ㅁㅂㅅㅇ "\x{110C}" => 'w', "\x{110E}" => 'c', "\x{110F}" => 'z', "\x{1110}" => 'x', # ㅈㅊㅋㅌ "\x{1111}" => 'v', "\x{1112}" => 'g', "\x{1101}" => 'R', "\x{1104}" => 'E', # ㅍㅎㄲ ㄸ "\x{1108}" => 'Q', "\x{110A}" => 'T', "\x{110D}" => 'W', # ㅃ ㅆ ㅉ #중성 "\x{1161}" => 'k', "\x{1163}" => 'i', "\x{1165}" => 'j', "\x{1167}" => 'u', # ㅏㅑㅓㅕ "\x{1169}" => 'h', "\x{116D}" => 'y', "\x{116E}" => 'n', "\x{1172}" => 'b', # ㅗㅛㅜㅠ "\x{1173}" => 'm', "\x{1175}" => 'l', # ㅡㅣ "\x{1162}" => 'o', "\x{1164}" => 'O', "\x{1166}" => 'p', "\x{1168}" => 'P', # ㅐㅒㅔㅖ #종성 "\x{11A8}" => 'r', "\x{11AB}" => 's', "\x{11AE}" => 'e', "\x{11AF}" => 'f', # ㄱㄴㄷㄹ "\x{11B7}" => 'a', "\x{11B8}" => 'q', "\x{11BA}" => 't', "\x{11BC}" => 'd', # ㅁㅂㅅㅇ "\x{11BD}" => 'w', "\x{11BE}" => 'c', "\x{11BF}" => 'z', "\x{11C0}" => 'x', # ㅈㅊㅋㅌ "\x{11C1}" => 'v', "\x{11C2}" => 'g', # ㅍㅎ "\x{11A9}" => 'R', "\x{11BB}" => 'T', # ㄲ ㅆ #특수문자 "\x{20}" => ' ' , "\x{A}" => "\n" , "\x{2E}" => '.' , "\x{2C}" => ',' , #Space Enter . , "\x{2D}" => '-' , #Number "\x{30}" => '0' , "\x{31}" => '1' , "\x{32}" => '2' , "\x{33}" => '3' , "\x{34}" => '4' , "\x{35}" => '5' , "\x{36}" => '6' , "\x{37}" => '7' , "\x{38}" => '8' , "\x{39}" => '9' , ); my @jamos = map { split //, decomposeJamo($_) }split //, decomposeSyllable($str); my $keys = '{HAN}'; foreach (@jamos) { $keys .= $hangle{$_} } # print "$strokes"; return $keys; }



- 아래는 스크립트 입니다. 공개하니 부끄럽네요 ㅡ_ㅠ

use strict;
use warnings;    
use Win32::GuiTest qw(:ALL);
use Win32::MediaPlayer;
use Hangle qw/transformation/;

my $file = 'background.mp3';
my $winmm = new Win32::MediaPlayer;  
$winmm->load($file);        
$winmm->play;                   
$winmm->volume(100);            

# notepad 시작
system("start notepad.exe");
sleep 3;

#전체 창 띄우기 
max_window();

#한글 키 입력
Win32::GuiTest::SendKeys("{HAN}");

#글씨체 및 폰트 바꾸기
font_change("휴먼편지체",36);
sleep 3;

writing("너를 만나기 전까진.");
waiting();
waiting();
newLine();

writing("내 마음은 차가운 겨울처럼 멈춰있는 신호등과 같았어.");
waiting();
waiting();
newLine();

writing("하지만 너를 만나면서 무뚝뚝하던 내가");
newLine(); # Enter 한줄 내리기 
writing("조금씩 웃고 있다는 걸 깨달았지.");
sleep 4;

# 전체 지우기
clear();

writing("때론 설레임으로 잠을 못 이루기도 하고,");
sleep 2;
newLine(); # Enter 한줄 내리기 

writing("너의 웃음소리가 귓가에 맴돌아 나도 모르게 미소 짓고,");
sleep 2;
newLine(); # Enter 한줄 내리기 

writing("데이트하는 날이면, 시계만 종일 쳐다보는 나를 발견했어.");
waiting();
waiting();
newLine(); # Enter 한줄 내리기
newLine(); # Enter 한줄 내리기

writing("그래.");
waiting();
waiting();
waiting();
writing(" 나 지금 설래이고 떨려.");
waiting();
waiting();
sleep 4;

# 전체 지우기
clear();

writing("지금 네 앞의 남자는");
sleep 3;
newLine();
writing("아직 부족하고 모자라지만,");
sleep 3;
newLine();
newLine();

writing("너만을 사랑하고");
sleep 1;
writing(" 너만을 아껴주는");
sleep 1;
writing(" 멋진 남자가 될께.");
sleep 3;

newLine();
newLine();

writing("우리 앞으로 ");
sleep 1;
writing("행복 하게 지내자 ");
Win32::GuiTest::SendKeys("+6+6");
sleep 3;
newLine();
newLine();

writing("그리고.");
waiting();
waiting();
waiting();

writing(" 사");
waiting();
waiting();
waiting();
writing("랑");
sleep 1;

# 빨리 지우기 
backspace(12);


#천천히 지우기 
backspace(1);
sleep 1;
backspace(1);
sleep 1;
backspace(1);
sleep 1;

writing(" 사랑한다");
writing(" 누구누구야");
Win32::GuiTest::SendKeys("!!");
sleep 5;

#notepad 종료하기
end();

#음악 종료
$winmm->pause;

# 동영상 FullScreen으로 재생
system('"C:\Program Files (x86)\Windows Media Player\wmplayer.exe" C:\동영상.wmv /fullscreen');

# 폰트 변경하기
sub font_change {
  my ( $font,$size ) = (@_);
  my $cmd = "%of".transformation($font)."{TAB}{TAB}".$size;
  Win32::GuiTest::SendKeys($cmd);
  sleep 2;
  Win32::GuiTest::SendKeys("~");
  sleep 3;
}

# 최대창으로 변경 
sub max_window{
   Win32::GuiTest::SendKeys("%{SPACE}x");
   sleep 3;
}

# 한글 변환해서 출력 
sub writing{
  my $text = shift;
  Win32::GuiTest::SendKeys(transformation($text));
}

# . 찍으며 1초씩 기다리기
sub waiting{
  Win32::GuiTest::SendKeys(".");
  sleep 1;	
}

# Enter 한줄 내리기
sub newLine{
  Win32::GuiTest::SendKeys("~");  
}

# Ctrl+A 후 Backspace 키로 전체 지우기
sub clear{
  Win32::GuiTest::SendKeys("^a{BACKSPACE}");
}

# Backspace 사용
sub backspace{
   my ($count) = shift;
   Win32::GuiTest::SendKeys("{BACKSPACE}") for(1..$count) ;
}

#NotePad 종료
sub end{
  Win32::GuiTest::SendKeys("%{F4}{TAB}{ENTER}");
}

Link : http://codepad.org/uPhPvpSx



글을 쓸때 참고했던 URL 입니다 (http://whitelove002.tistory.com/290) 

작가님께 감사합니다 ^^;;



4년만에 함께한 Korean Perl workshop 아주 흥미로웠고 재밌었던 주제가 많았습니다.

특히 Web 분야가 상당히 많이 발전하고 있더군요.

배울점도 많고, 좋은 사람도 많이 만났습니다.


@Gypark 님을 드디어 뵙는 역사적인 날이기도 했구요 ㅋㅋ


좋은 행사를 준비해주신 관리자 분들께 감사드리구요!

11월 모임 때 뵙겠습니다^^/


http://event.perl.kr/kpw2012/


아래는 동영상입니다 ㅠ 흑엽님이 올려주셨는데.. 공개해도 될지..


신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 2 Comment 7
2012.10.11 00:45

[KPW2012] Korean Perl Workshop 2012 - 초대합니다 :)

회사생활에 바쁘다보니 어느새 블로그를 쓴지도 꾀 오래 되었네요^^;

간만에 쓰는글인데 좋은 정보 알려드려야죠!! ㅋ


Korean Perl Workshop 2012 

KPW2012 가 10월 20일(토요일)에 서울에서 진행된다는 사실!


Perl 을 즐겨쓰고 좋아하는 사람들과

서로의 지식을 공유하는 자리로 

재밌게 했던 프로젝트와 알찬 정보 , 

그리고 최신 기술들을 워크샵에서 들을 수 있습니다!


으아~ 이런 엄청난 컨퍼런스를 꼭 가셔야죠! 

어서 이날 시간 비우시고 고고싱 합시다!!



Korean Perl 

Workshop 2012

on Sat. Oct. 20th, 2012 



크고 작은 세미나는 중간에 지속적으로 있었지만 

이런 큰 행사는 오랜만이라 긴장되고 기대 되네요!

등록은 아래 주소에서 하시면 됩니다.


아참!! 참가비 만원!

이정도야~ >_< 


많이많이 등록하고 참가해주세요~



 

신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 1 Comment 0
2012.04.12 22:05

8. Registry File Parser Source code

지금까지 Harlan Carvey님의 Offline Registry File Parser 버전 1.1의 코드를 

조금씩 코드를 추가시키며 완성해보는 작업을 하였습니다.

이 코드는 2006년에 작성 되었으며, NT Registry Hive access library 인 ntreg.h 를 참고하여 만들었다고 합니다. 


Harlan Carvey님은 다들 아시겠지만, http://windowsir.blogspot.com/ 블로그를 운영하고, 

Forensic 책으로 유명한 'Windows Forensic Analysis' 를 쓰신 분입니다. 


코드도 직접 짜시고 책까지 쓰셨으니 대박이죠!! 

국내에는 '인사이드 윈도우즈 포렌식' 으로 2010년에 번역서가 나왔습니다 

저는 이때 알았네요 ^^;; 

( 번역서는 나오자말자 친한 동생을 통해 볼 수 있었습니다. ㅋㅋㅋ Link


아래는 원본소스코를 강좌를 쓰기 위해서 재작성했던 코드의 전체소스입니다.


use strict;
use warnings;

my $ADJUST  = 0x1004;	

#registry Value Type
my %regtypes = (0 => "REG_NONE",
				1 => "REG_SZ",
	            2 => "REG_EXPAND_SZ",
	            3 => "REG_BINARY",
	            4 => "REG_DWORD",
	            5 => "REG_DWORD_BIG_ENDIAN",
	            6 => "REG_LINK",
	            7 => "REG_MULTI_SZ",
	            8 => "REG_RESOURCE_LIST",
	            9 => "REG_FULL_RESOURCE_DESCRIPTOR",
	            10 => "REG_RESOURCE_REQUIREMENTS_LIST");

# Special list for translating the UserAssist (ROT-13) key value names
my @WinXPua = qw/{5E6AB780-7743-11CF-A12B-00AA004AE837}
            {75048700-EF1F-11D0-9888-006097DEACF9}/;
my @Win7ua = qw/{CEBFF5CD-ACE2-4F4F-9178-9926F41749EA}
            {F4E57C4B-2036-45F0-A9AB-443BCFE33D9F}/;
			
my $file = shift || die "You must enter a filename.\n";
open my $reg, '<', $file  or die "cannot open [$file] file: $!";

my ($node,$offset) = locateRecord($ADJUST);
my $nt = _getNodeType($offset); 

if ($nt == 0x6b6e) { # 'nk' record 일 경우 파싱을 시작
	parseNkRecords("",$offset);
}
else {
	printf "Node not an nk node: 0x%x\n",$nt;
	die;
}
close $reg; 


# nk 의 root key 값을 찾는 코드

sub locateRecord {
	my $offset = shift;
	my $record;
	seek($reg,$offset,0);
	while(1) {
		read($reg,$record,4);
		my ($tag,$id) = unpack("SS",$record);
		if ($tag == 0x6b6e && $id == 0x2c) { 
			# print "nk record located.\n";
			return("nk",$offset);
		}
		$offset = $offset + 2;
		seek($reg,$offset,0);
	}
}


# offset으로부터 2byte를 읽어와 unpack 을 사용하여 node의 ID를 얻는 방법

sub _getNodeType {
	my $offset = shift;
	my $record;
	seek($reg,$offset,0);
	my $bytes = read($reg,$record,2);
	if ($bytes == 2) {
		return unpack("S",$record);
	}
	else {
		print "_getNodeType error - only $bytes read.";
		return;
	}
}

# nk record 들을 파싱하는 부분입니다. 

sub parseNkRecords {
	my ($name, $offset) = (@_);
	my %nk = readNkRecord($offset);
	print $name."\\".$nk{keyname}."\n"; 
	print "LastWrite time: ".gmtime(getTime($nk{time1},$nk{time2}))."\n";
=subkey infomation 정보는 출력에서 제외 시켰습니다	
	print "Number of subkeys : ".$nk{no_subkeys}."\n";
	print "Pointer to the subkey-list : ".$nk{ofs_lf}."\n";
	print "Number of values : ".$nk{no_values}."\n";
	print "Pointer to the value-list for values : ".$nk{ofs_vallist}."\n";
	print "Pointer to the SK record : ".$nk{ofs_sk}."\n";
	print "Pointer to the class name : ".$nk{ofs_classname}."\n";
	print "Key name length : ".$nk{len_name}."\n";
	print "Class name length : ".$nk{len_classname}."\n";
=cut
	if ($nk{no_values} > 0) { 
		my @ofs_vallist = readValList(($nk{ofs_vallist} + $ADJUST),$nk{no_values});
		foreach my $i (0..(scalar(@ofs_vallist) - 1)) {
			my %vk = readVkRecord($ofs_vallist[$i] + $ADJUST);	
			if ($nk{keyname} eq "Count") {
				foreach my $u (@Win7ua) {
					if (grep(/$u/,$name)) {
						$vk{valname} =~ tr/N-ZA-Mn-za-m/A-Za-z/;						
					}					
				}				
			}			
			print "\t--> ".$vk{valname}.";".$regtypes{$vk{val_type}}.";".$vk{data}."\n";
		}
		print "\n";
	}
	
	if ($nk{no_subkeys} > 0) {
		my $nt = _getNodeType($nk{ofs_lf} + $ADJUST);
		if ($nt == 0x666c || $nt == 0x686c) {  # lf = 0x666c , lh = 0x686c
			my %lf = readLfList($nk{ofs_lf} + $ADJUST);
			foreach my $ofs_lf (keys %lf) {
				parseNkRecords($name."\\".$nk{keyname},$ofs_lf + $ADJUST);
			}
		}
		elsif ($nt == 0x6972) {  # ri = 0x6972
			my @ri = readRiList($nk{ofs_lf} + $ADJUST);
			foreach (@ri) {
				parseLiRecords($name."\\".$nk{keyname},$_ + $ADJUST);
			}
		}
		elsif ($nt == 0x696c) {  # li = 0x696c
			parseLiRecords($name."\\".$nk{keyname},$nk{ofs_lf} + $ADJUST);
		}
		else {
			printf "***Unrecognized node type : 0x%x\n",$nt;
		}
	}
}


# nk record를 읽어온 뒤 각각의 변수들로 저장시킨다.

sub readNkRecord {
	my $offset = shift;
	my $record;
	my %nk = ();
	seek($reg,$offset,0);
	my $bytes = read($reg,$record,76);
	if ($bytes == 76) {
		my (@recs)	= unpack("SSL3LLLLLLLLLL4LSS",$record);
		$nk{id}		= $recs[0];
		$nk{type}		= $recs[1];
		$nk{time1}	= $recs[2];
		$nk{time2}	= $recs[3];
 		$nk{time3}	= $recs[4];
		$nk{no_subkeys}	= $recs[6];
		$nk{ofs_lf}		= $recs[8];
		$nk{no_values}	= $recs[10];
		$nk{ofs_vallist}	= $recs[11];
		$nk{ofs_sk}	= $recs[12];
		$nk{ofs_classname}	= $recs[13];
		$nk{len_name}	= $recs[19];
		$nk{len_classname}	= $recs[20];

		# key의 이름을 알아내어 저장한다		
		seek($reg,$offset + 76,0);
		read($reg,$record,$nk{len_name});
		$nk{keyname}       = $record;

		# 여기까지 읽은 전체 바이트의 수는 ($num_bytes + $nk_rec{len_name}) 입니다.
		# 다시 말하면 nk의 76byte + nk의 keyname 길이만큼 입니다.
		# 이 값들을 활용하기 위해 hash 값을 return 시킵니다.
		return %nk;
	}
	else {
		print "readNkRecord bytes read error: ".$bytes;
		return;
	}
}


# 2개의 4Byte time값을 64-bit NT timestamp 값으로 변환해주는 코드

sub getTime() {
	my ($lo,$hi) = (@_);
	my $t;

	if ($lo == 0 && $hi == 0) {
		$t = 0;
	} else {
		$lo -= 0xd53e8000;
		$hi -= 0x019db1de;
		$t = int($hi*429.4967296 + $lo/1e7);
	};
	$t = 0 if ($t < 0);
	return $t;
}

# lf/lh 의 주소를 읽어와서 하위 nk Record의 리스트를 뽑는 코드

sub readLfList {
	my $offset = shift;
	my $record;
	my $num_bytes = 4;
	seek($reg,$offset,0);
	my $bytes = read($reg,$record,$num_bytes);
	if ($bytes == $num_bytes) {
		my($id, $no_keys) = unpack("SS",$record); #id 는 lf/lh 
		seek($reg,$offset + $num_bytes,0);
		$bytes = read($reg,$record,(2 * 4 * $no_keys));
		
		my $iterations = ($bytes/4);
		my $step = 1;
		my $temp;
		my %lf;
		# 4개의 문자를 읽어온다.
		foreach my $i (0..($iterations - 1)) {
			my $str = substr($record,$i*4,4);
			if ($step%2) {
				$temp = unpack("L",$str);
			}
			else {				
				$lf{$temp} = $str;
			}
			$step++;
		}		
		return %lf;
	}
	else {
		print "readLfList bytes read error: ".$bytes;
		return;
	}
}

# ri 의 사이즈만큼 주소를 읽어와 리스트로 반환한다.

sub readRiList {
	my $offset = shift;
	my $record;
	seek($reg,$offset,0);
	my $bytes = read($reg,$record,4);
	my ($id,$num) = unpack("SS",$record);
	seek($reg,$offset + 4,0);
	$bytes = read($reg,$record,$num * 4);
	return unpack("L*",$record);
}

# li record들의 주소가 nk record 나 subkey 일때 다시 재귀적으로 탐색한다.

sub parseLiRecords {
	my ($name,$offset)  = (@_);
	my @li_list = readRiList($offset);
	foreach my $ofs_nk (@li_list) {
		my $nt = _getNodeType($ofs_nk + $ADJUST);
		if ($nt == 0x6b6e) {
			parseNkRecords($name,$ofs_nk + $ADJUST);
		}
		elsif ($nt == 0x696c) {
			parseLiRecords($name,$ofs_nk + $ADJUST);
		}
		else {
			printf "**Unrecognized node type : 0x%x\n",$nt;
		}
	}
}

# Value Record 의 이름 및 값들을 형식에 따라 읽어온 뒤 해시 값으로 반환

sub readVkRecord {
	my $offset = shift;
	my $record;
	my %vk = ();
	seek($reg,$offset,0);
	my $bytes = read($reg,$record,20);
	if ($bytes == 20) {

		my (@recs)    = unpack("SSLLLSS",$record);
		$vk{val_type} = 0;
		$vk{id}       = $recs[0];
		$vk{len_name} = $recs[1];
		$vk{len_data} = $recs[2];
		$vk{ofs_data} = $recs[3];
		$vk{val_type} = $recs[4];
		$vk{flag}     = $recs[5];
		# value 의 이름을 읽어온다.
		if ( $vk{len_name} == 0) {
			$vk{valname} = "Default";
			#vk{val_type} 값이 잘 못된 값이 들어가기도 한다. 
			$vk{val_type} = 1; # REG_SZ 로 설정
			$vk{data} = 0;
			return %vk;
		}
		else {
			seek($reg,$offset + 20,0);
			read($reg,$record,$vk{len_name});
			$vk{valname}  = $record;
		}
		
		# 각 valuetype에 따라 데이터를 출력하는 방법을 다르게 하기 위한 작업
		if ($vk{len_data} & 0x80000000 || $vk{val_type} == 4) {
			# $vk{len_data}가 0x80000000거나 REG_DWORD 일 경우 아래 형식으로 저장
			$vk{data} = $vk{ofs_data};			
			$vk{data} = "" if ($vk{val_type} == 7);
			$vk{data} = chr($vk{data}) if ($vk{val_type} == 1);
		}
		else {
			# REG_SZ , REG_EXPAND_SZ , REG_MULTI_SZ 일 시에 ASCII 값으로 변환
			$vk{data} = _getValueData($vk{ofs_data} + $ADJUST,$vk{len_data});
			$vk{data} = _uniToAscii($vk{data}) if ($vk{val_type} == 1 ||
			                                       $vk{val_type} == 2 ||
			                                       $vk{val_type} == 7);
		}
		# REG_BINARY , REG_RESOURCE_LIST , REG_RESOURCE_REQUIREMENTS_LIST 일 시 이진값으로 변환
		$vk{data} = _translateBinary( $vk{data}) if ($vk{val_type} == 3 || 
									$vk{val_type} == 8 ||
									$vk{val_type} == 10);			
		return %vk;
	}
	else {
		print "readVkRecord bytes read error: ".$bytes;
		return;
	}
}

#넘겨받은 길이 만큼 데이터를 읽어 값을 반환

sub _getValueData {
	my ($offset,$len ) = (@_);
	my $record;
	seek($reg,$offset,0);
	my $bytes = read($reg,$record,$len);
	if ($bytes == $len) {
		return $record;
	}
	else {
		print "_getValData error: $bytes of $len bytes read.";
		return;
	}
}

# 유니코드 문자열을 ASCII로 변환

sub _uniToAscii {
	my $str = shift;
	my $len = length($str);
	my $newlen = $len - 1;
	my @str2;
	my @str1 = split(//,$str,$len);
	foreach my $i (0..($len - 1)) {
		if ($i % 2) {
			# 아스키코드 일경우에는 홀수값이 \00이라 값을 읽을 필요가 없다.
		}
		else {
			push(@str2,$str1[$i]);
		}
	}	
	return join('',@str2);
}

# 데이터를 2진 값으로 변환하여 출력

sub _translateBinary {
	my $str = unpack("H*",$_[0]);	
	my $len = length($str);
	my @nstr = split(//,$str,$len);
	my @list;
	foreach (0..($len/2)-1) { # 기존소스에는 -1이 없어 warning 발생
		push(@list,$nstr[$_*2].$nstr[($_*2)+1]);
	}
	return join(' ',@list);
}

# value 리스트의 사이즈를 만큼의 주소를 @ofs_val배열하여 반환한다.

sub readValList {
	my ($offset,$num_vals) = (@_);
	my $record;
	my $bytes_to_read = $num_vals * 4;
	seek($reg,$offset,0);
	my $bytes = read($reg,$record,$bytes_to_read);
	if ($bytes == $bytes_to_read) {
		my @ofs_val = unpack("L*",$record);
		if (scalar(@ofs_val) == $num_vals) {
			return @ofs_val;
		}
		else {
			print "readValList bytes read error: ".$bytes;
			return;
		}
	}
}


2006년에 작성된 코드지만, 레지스트리 Hive 파일구조가 변하지 않으므로 

시간이 지나도 여전히 좋은 자료라 생각되네요!!

여기까지의 작업은 Registry Hive 파일의 복구하여 데이터를 뽑아내는 작업만 하고 있어,

Forensic의 중요 데이터를 뽑는 작업은 하지 않고 있습니다.


Forensic에 필요한 데이터가 젤 중요한데 그냥 연결만 시켜놓고 끝낼 순 없겠죠??


다음주 부터는 이 다음 버전인 Registry Ripper (Version 2.2)  코드를 보면서 

강좌를 다시 시작하겠습니다. ^^/



신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 6
2012.04.06 23:56

4. NK Record

NK Record 들은 레지스트리 구조를 연결하는데 가장 중요한 역활들을 해주는 Record 입니다.

이 Record는 각 Key 에 따른 하위 목록들의 연결값들을 가지고 있고 최종으로 수정한 시간도 담겨 있습니다.

이 장에서는 NK Record 의 세부적인 값들을 추출하여 나열하는 샘플을 만들어 보겠습니다. 람쥐..^^;

최근 일주일동안 블로그에 열심히 글을 올렸습니다. 

오랜만에 강좌를 적어서 그런지 홍보를 안해서 그런지

조회수는 높은데 댓글이 없군요 ㅡ_ㅠ


글을 적는 재미는 쏠쏠합니다~

피드백이 좀 들어왔으면 하는데.. 

딴지도 환영입니다.( 적당히만 해주시면 ㅡ_ㅠ...)


그러면 시작~~!


Key Records 는 각 Cell 에 대한 사이즈나 정보들을 담고 있습니다. 

첫번째 4Byte 는 사이즈가 담겨 있으며, 두번째 값으로는 "nk" 라는 signature를 가지게 됩니다.

여기 nk가 없다면 이건 Key Records가 아닌겁니다!

nk 키로 부터 시작해서 Subkey 를 연결하는 구조로 되어 있기 때문에,

이 정보들을 소중하게 간직하셔야 합니다 :)


이번에는 코드를 먼저 보면서 설명을 드리겠습니다.


use strict;
use warnings;

my $ADJUST  = 0x1004;	
my $file = shift || die "You must enter a filename.\n";
open my $reg, '<', $file  or die "cannot open [$file] file: $!";

my ($node,$offset) = locateRecord($ADJUST);
my $nt = _getNodeType($offset); 

if ($nt == 0x6b6e) { # 'nk' record 일 경우 파싱을 시작 합니다.
	parseNkRecords("",$offset);
}
else {
	printf "Node not an nk node: 0x%x\n",$nt;
	die;
}
close $reg; 


# nk 의 root key 값을 찾는 코드

sub locateRecord {
	my $offset = shift;
	my $record;
	seek($reg,$offset,0);
	while(1) {
		read($reg,$record,4);
		my ($tag,$id) = unpack("SS",$record);
		if ($tag == 0x6b6e && $id == 0x2c) { 
			# print "nk record located.\n";
			return("nk",$offset);
		}
		$offset = $offset + 2;
		seek($reg,$offset,0);
	}
}


# offset으로부터 2byte를 읽어와 unpack 을 사용하여 node의 ID를 얻는 방법입니다.
# 이 함수를 하나 만들어 두면 앞으로 각 Record 의 타입을 확인하기 편하죠!

sub _getNodeType {
	my $offset = $_[0];
	my $record;
	seek($reg,$offset,0);
	my $bytes = read($reg,$record,2);
	if ($bytes == 2) {
		return unpack("S",$record);
	}
	else {
		print "_getNodeType error - only $bytes read.";
		return;
	}
}

# nk record 들을 파싱하는 부분입니다. 
# 파싱한 후 nk 의 값들을 traverse 하는 코드들은 다음장에서 :)

sub parseNkRecords {
	my ($name, $offset) = (@_);
	my %nk = readNkRecord($offset);
	#nk record 의 정보들을 출력합니다. 설명까지 앞에 다 붙였습니다! 
	print $name."\\".$nk{keyname}."\n"; 
	print "LastWrite time: ".gmtime(getTime($nk{time1},$nk{time2}))."\n";
	print "Number of subkeys : ".$nk{no_subkeys}."\n";
	print "Pointer to the subkey-list : ".$nk{ofs_lf}."\n";
	print "Number of values : ".$nk{no_values}."\n";
	print "Pointer to the value-list for values : ".$nk{ofs_vallist}."\n";
	print "Pointer to the SK record : ".$nk{ofs_sk}."\n";
	print "Pointer to the class name : ".$nk{ofs_classname}."\n";
	print "Key name length : ".$nk{len_name}."\n";
	print "Class name length : ".$nk{len_classname}."\n";
	# 이후에 Key들을 연결해줄 코드들이 쭈욱~~ 붙게 됩니다.
}


# 위의 표에서 본 값들을 전부 읽어와서 각각의 변수들로 저장시킵니다.
# perl 의 hash를 통해서 하나하나 이름을 붙여 깔끔하게 저장하네요 :)

sub readNkRecord {
	my $offset = shift;
	my $record;
	my %nk = ();
	seek($reg,$offset,0);
	my $bytes = read($reg,$record,76);
	if ($bytes == 76) {
		# unpack의 알흠다운 활용법입니다.
		my (@recs)	= unpack("SSL3LLLLLLLLLL4LSS",$record);
		$nk{id}		= $recs[0];
		$nk{type}		= $recs[1];
		$nk{time1}	= $recs[2];
		$nk{time2}	= $recs[3];
 		$nk{time3}	= $recs[4];
		$nk{no_subkeys}	= $recs[6];
		$nk{ofs_lf}		= $recs[8];
		$nk{no_values}	= $recs[10];
		$nk{ofs_vallist}	= $recs[11];
		$nk{ofs_sk}	= $recs[12];
		$nk{ofs_classname}	= $recs[13];
		$nk{len_name}	= $recs[19];
		$nk{len_classname}	= $recs[20];

		# key의 이름을 알아내어 저장합니다		
		seek($reg,$offset + 76,0);
		read($reg,$record,$nk{len_name});
		$nk{keyname}       = $record;

		# 여기까지 읽은 전체 바이트의 수는 ($num_bytes + $nk_rec{len_name}) 입니다.
		# 다시 말하면 nk의 76byte + nk의 keyname 길이만큼 입니다.
		# 이 값들을 활용하기 위해 hash 값을 return 시킵니다.
		return %nk;
	}
	else {
		print "readNkRecord bytes read error: ".$bytes;
		return;
	}
}


# 2개의 4Byte time값을 64-bit NT timestamp 값으로 변환해주는 코드입니다.

sub getTime() {
	my $lo = shift;
	my $hi = shift;
	my $t;

	if ($lo == 0 && $hi == 0) {
		$t = 0;
	} else {
		$lo -= 0xd53e8000;
		$hi -= 0x019db1de;
		$t = int($hi*429.4967296 + $lo/1e7);
	};
	$t = 0 if ($t < 0);
	return $t;
}

!!! 

코드가 엄청 늘어 났습니다. 

나중에 각각의 키들의 offset 에 따라서 재귀적으로 함수를 호출해야 하기 

때문에 코드를 함수로 빼는 작업이 중요합니다.

위의 코드를 설명을 드리자면 

가장 처음의 nk record 를 접근해서 record의 값을 추출한 뒤 해시에 저장한 후에

그 값 들을 출력해주고 있습니다.


코드 실행의 결과는 아래와 같습니다.

>perl rega.pl SAM

\SAM

LastWrite time: Sun Jul  4 09:33:18 2010

Number of subkeys : 1

Pointer to the subkey-list : 504

Number of values : 0

Pointer to the value-list for values : 4294967295

Pointer to the SK record : 120

Pointer to the class name : 4294967295

Key name length : 3

Class name length : 0

음?? value-lis의 offset의 값들이 말도 안되는 숫자가 나오는 이유는

values가 0개기 때문입니다. Class name의 offset 도 마찬가지구요 :)


forensic 관점에서 연결해주는 offset 이나 각 number 들이 중요하진 않습니다.

여기서 빨간색으로 표시한 key 이름과 LastWrite의 시간이 가장 중요하죠.

나중에 분석을 할 때나 UI 도구을 만들때도 이 데이터들이 중요한 역활을 합니다.


그럼 오늘 강좌는 여기까지 하고.. 

불타는 금요일 + 주말  보내세요~~ :)


신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 0
2012.04.04 19:10

2. Registry hive structure

Registry Hive 파일을 통해 원본  레지스트리값들을 알아내기 위해서는 먼저 Hive 파일의 구조를 알아야 합니다.

이 장에서는 샘플 Hive 파일을 추출하여 Hex Editor를 통해 값을 확인하고 프로그래밍으로 Hive 파일을 불러와서 

값들을 체크하는 샘플을 만들어 보도록 하겠습니다.


레지스트리 Hive 파일을 분석하기 위해서는 먼저 Hive 파일을 추출해야 합니다.

정확한 레지스트리 Hive 파일을 얻어오기 위해서는 컴퓨터를 종료 한 뒤, 

하드 디스크에 있는 Hive 파일을 추출하여 사용하는게 가장 좋은 방법이지만


하드 디스크를 빼려면 본체도 열어야 하고 나사도 풀어야 하고 ㅡ_ㅠ

보통 힘든일이 아닙니다. (쉬우신 분들도 있겠지만요 ^^;)


그래서 간단하게 샘플 파일을 얻는 방법을 설명해 드리겠습니다.

자신의 현재 컴퓨터에서도 가능합니다.


1. 실행창에서 레지스트리 편집기인 regedit 를 입력합니다.


2. HKEY_LOCAL_MACHINE 의 SAM을 선택하여 내보내기를 누릅니다.

(SAM에 값이 없는 것 같지만 숨겨져 있을뿐 중요한 정보가 많이 담겨져 있습니다)


3. 내보내기를 할 때 파일형식을 레지스트리 하이브파일로 선택해주셔야 합니다!


위와 같이 진행하시면 현재 컴퓨터의 레지스트리 Hive 샘플 파일인 SAM 파일을 얻을 수가 있습니다. +_+


레지스트리 Hive 파일의 전체 구조는 아래와 같습니다. 

첫번째로 Base Block 가 존재하며 'regf'라는 시퀀스를 가지고 있습니다.

이 Base Block은 4096(0x1000)Byte로 이루어져 있으며 

Hive 파일 이름, 첫번째 키 레코드의 주소, 마지막 hbin 파일 주소 등이 담겨 있습니다.

이 블럭에는 hive 파일의 전체적으로 중요한 정보들을 저장하고 있습니다.

Hive 파일의 습니다.


이런건 눈으로 봐야 하는데.. Hex Editor로 파일을 한번 열어 보겠습니다.

처음에 'regf' 보이시죠? 이 시퀀스가 레지스트리 Hive 파일이라는 것을 알려주는 부분입니다.


그리고 4096Byte를 봤을 때 시퀀스 값이 'hbin' 이라는 것도 확인을 할 수 있습니다 :)


레지스트리의 Hive 파일의 스펙은 정확히 공개되지 않았습니다. 

그래서 지속적으로 그 값들을 확인하기 위한 작업들이 이루어지고 있으며

그래도 제일 분석이 잘 된 The WindowsNT Registry File Format.pdf 파일의 맨 마지막장에 보시면 

각 구조에 대한 값들을 자세하게 확인 할 수 있습니다. ( 정확하지 않은 부분은 Unknown 이나 물음표를 넣어놨더군요 ^^;)



앞서 설명드린 Base Block 파일은 위와 같은 정보들을 가지고 있으며, 

이 값들을 perl을 사용하여 추출하여 보도록 하겠습니다.

( timestamp 는 기록이 정확하게 되어 있지 않아 제외 시켰습니다. )


> rega.pl 


use strict;
use warnings;

my $record;
my $offset=0;
my $file = shift || die "You must enter a filename.\n";
open my $reg, '<', $file  or die "cannot open [$file] file: $!";

# Magic Number 
read($reg,$record,4);
my $magic = unpack("A4",$record);
print $magic,"\n";

#root key offset
seek($reg,0x24,0);
read($reg,$record,4);
my $rootkey = unpack("L",$record);
print $rootkey,"\n";

#file name
seek($reg,0x30,0);
read($reg,$record,64);
my $filename = unpack("A*",$record);
printf $filename;


코드의 문법상 어려운 부분은 없을 것입니다. 
unpack 문서는 아래 링크를 참고 하시면 됩니다.

rega.pl 파일을 실행을 시켰을 때 결과값이 아래와 같이 나오면 정상적으로 추출 된 것입니다.

>perl rega.pl SAM

regf

32

\S y s t e m R o o t \ S y s t e m 3 2 \ C o n f i g \ S A M

※ 현재 컴퓨터에서 추출한 샘플 파일일 경우에는 아래 경로가 나오지 않습니다


레지스트리 Hive 파일을 알리는 'regf' 와 root key 값을 나타내는 32(0x20) 그리고 

SAM 파일이 위치한 전체경로를 확인 할 수 있습니다 :)


신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 1
2010.12.01 20:10

2010 Korea Perl Advent Calendar




http://advent.perl.kr

Perl 커뮤니티에는 매년 크리스마스 4주 전부터 Advent Calendar라는 것을 만들어서 
유용한 팁이나 정보들을 크리스마스 때까지 하나씩 올리곤 합니다.

매년 해외에서만 했고 한국에서는 이루어지지 않다가 
드디어 이번 2010년에는 Advent Calendar 가 열렸습니다 :)

진행하시는 분의 순서는 아래와 같고, 
글을 쓰고 싶으신 분들은 아래에 댓글을 달아주시면 감사하겠습니다!


12/1 aer0
12/2 aquative
12/3 jakerorg
12/4 gypark
12/5 ainvyu
12/6 popeye92
12/7 sng2c
12/8 kiseok7
12/9 keedi
12/10 eeyees
12/11 y0ngbin
12/12 dalinaum
12/13 yykim
12/14 corund
12/15 honeyperl
12/16 am0c
12/17 luzluna
12/18 ascendo
12/19 yuni_kim
12/20 jeen_lee
12/21 darjeeling
12/22 vohrmana
12/23 purewish
12/24 hshong

좋은 내용들이 많습니다~ 꼭 읽어보세요!

신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 1 Comment 2
2010.11.10 19:30

perl URI::Escape 모듈


얼마전 친구의 요청으로 지오코딩 API 를 사용해서
주소의 좌표를 얻어야 하는 코드를 작성할 일이  생겼습니다.

지오코딩 API 의 링크 : http://code.google.com/intl/ko/apis/maps/documentation/geocoding/

저는 모바일 프로그래밍은 관심이 별로 없는데 들리는 이야기로는
대부분 이 API 를 사용해서 좌표를 얻어 모바일에서 처리한다고 하네요 ^^;

그래서 친구한테 이 API 를 사용하면 쉽게 되겠네~ 해서
코드를 바로 짰습니다.

2바이트의 문자가 url에 그대로 들어가면 브라우저에 따라
인식못하고 글자가 깨지는 현상이 일어나기 때문에
url 을 변환해주는 코드를 작성해야 합니다.

기본적으로 많이 사용하는 Perl 코드는 아래와 같습니다.


Perl URL Encode & Decode String

Here's an excellent way to encode strings that are going to be placed in a URL:

$str =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;

Likely, "page_given_string.php" will want to decode $str back into something useful:

$str =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;


원문 Link : http://support.internetconnection.net/CODE_LIBRARY/Perl_URL_Encode_and_Decode.shtml

코드상으로 처리해도 상관은 없지만,
Perl 에서는 이것을 쉽게 처리할 수 있도록 모듈을 제공하고 있습니다.



URI::Escape

Escape and unescape unsafe characters
URI-1.56***** (2 Reviews) - 06 Oct 2010 - Gisle Aas





이 모듈을 쓰면 예를들어 "부산 부산진구 부암3동 441-3" 문자열이

%BA%CE%BB%EA%20%BA%CE%BB%EA%C1%F8%B1%B8%20%BA%CE%BE%CF3%B5%BF%20441-3



이런 형식으로 변환되게 됩니다.
그런데 이 주소로 지오코딩 API를 사용하여 쿼리를 날리니 값을 받을 수 없는 겁니다.

이상하다 싶어 실제 API 값을 살펴보니
"부산 부산진구 부암3동 441-3"  주소가 아래와 같이 변환이 되었습니다.

%EB%B6%80%EC%82%B0%20%EB%B6%80%EC%82%B0%EC%A7%84%EA%B5%AC%20%EB%B6%80%EC%95%943%EB%8F%99%20441-3

자세히 살펴보다보니
아.. URL 주소가 UTF-8로 되어 있어서 이것을 인코딩 시키면 되구나..
생각이 들더군요.

URI::Escape 모듈에는 uri_escape_utf8 이라는
함수도 존재하기 때문에 간단히 이 함수를 쓰면
해결이 되겠구나 라고 생각했는데...

%C2%BA%C3%8E%C2%BB%C3%AA%20%C2%BA%C3%8E%C2%BB%C3%AA%C3%81%C3%B8%C2%B1%C2%B8%20%C2%BA%C3%8E%C2%BE%C3%8F3%C2%B5%C2%BF%20441-3

두둥;; 전혀 다른값이 나오는 겁니다..
고민고민을 하다가 Perl 커뮤니티에 들어가서 물어보니
인코딩이 utf-8인 터미널에서 잘 돌아간다는 것을 알게 되었습니다. ㅠ_ㅠ

즉 펄내부유니코드 포멧을 utf8인코딩 바이트시퀀스로 바꾸어서
 uri_escape 를 사용해야 한다는 정리!

이 단순한 문제때문에 야후 거기 API 로 바꿀 생각까지 했습니다 ㅎㅎ;

혹시나 지오코딩 API 를 사용할때
문제를 격을지도 모를 분들을 위해 코드 정리!!  :-)


1
2
3
4
5
6
7
8
9
10
use strict;
use Encode qw/encode decode/;
use URI::Escape;
use LWP::Simple;
sub _e{ decode('cp-949',shift)  };
sub _e1{ encode('cp-949',shift); }
my $address = uri_escape_utf8( _e("부산 부산진구 부암3동 441-3"));
my $url = "http://maps.google.com/maps/geo?output=xml&q=$address";
my $location = _e1(get($url));
print $location;

원본 Link : http://codepad.org/ePUDSmgm


도움을 주신 a3r0님과 am0c 님 감사합니다
JEEN님은 별로.. ㅋㅋㅋ
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 2 Comment 3
2010.09.13 05:44

Naver Perl 카페회원 1000명을 돌파!




네이버에 운영중인 Perl Community & Study 카페 회원이

드디어 1000명을 넘어섰습니다.



Perl 카페는 세간의 이슈를 받지 않았고,

별 다른 홍보활동도 하지 않았습니다.

 

그럼에도 불구하고 프로그래밍 언어인 Perl 을 좋아하고

관심있는 회원이 1000명이나 모였다는 것은 너무 대단하고,

감동적인 일이라 생각합니다.

 

 

제가 처음에 이 카페를 만들었을 당시,

perl 을 열심히 배우고 있었고,

perl 을 너무나 좋아하던 시기 였습니다.

 

프로그래밍을 익히던 중 매너리즘에 빠졌던 당시,

광활한 세계를 느끼게 해주었고,

 

Perl 과 관련하여 많은 사람을 만나게 해주었던,

저에게는 너무나 소중했던 언어였습니다.

 

최근,카페장인 제가 공부하는 시기에서 일을 해야하는 시기로 넘어가

카페 관리에도 많이 소홀해 졌지만,

처음에 Perl 을 배울때 따스히 맞아줬던 분들을 기억하며,

언제든지 처음 배우시는 분이 있다면 저 또한 따스하게 맞아줘야 한다고 생각했습니다.

 
제가 적은 이 글을 부끄럽지 않도록 이제라도 많이 신경을 쓰겠습니다~~ ^^;

 

Perl 카페를 지켜보고 있고 들어와 주시는 회원 여러분들께 감사드리며

앞으로 Perl 카페의 행보에 대해서도 많은 기대 부탁드립니다.

 


기쁜 소식을 한가지 전해드리자면,

Perl 계의 정신적 지주이신 @keedi 님과 @y0ngbin 님이 두분이서 Perl 로 운영되는

회사를 개업하셨다고 합니다 :)

 

앞으로 많은 발전하셔서, 우리 카페에서 회원들 많이 뽑아가셨으면 하는 바램입니다 >_<

신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 0 Comment 10
2010.07.30 02:16

드디어 "Perl 6"이 출시 되었습니다 :)


Perl 6이 Rakudo Star 라는 이름으로 릴리즈 되었습니다.

Rakudo Star - a useful, usable, "early adopter" distribution of Perl 6

http://rakudo.org/node/75

여기서 early adopters 라는 이름을 달고 출시를 한 이유는

perl 6 출시에 앞서 몇가지 버그가 있음을 잘 알고

사용자와 피드백을 얻기 위해서 이렇게 이름을 달았다고 합니다.



Perl 6 에서의 멋진 기능들 입니다 :)

  • Perl 6 grammars and regexes
  • formal parameter lists and signatures
  • metaoperators
  • gradual typing
  • a powerful object model, including roles and classes
  • lazy list evaluation
  • multiple dispatch
  • smart matching
  • junctions and autothreading
  • operator overloading (limited forms for now)
  • introspection
  • currying
  • a rich library of builtin operators, functions, and types
  • an interactive read-evaluation-print loop
  • Unicode at the codepoint level
  • resumable exceptions


KLDP 에 올리신 @aer0 님의 축하글 ~



Perl6을 사용하고 싶으시다면 아래 링크로 고고!!


Rakudo Star "perl 6" 다운로드 경로입니다.

신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 2 Comment 3
2010.06.16 08:41

소스 다이어트의 적절한 예


얼마전 친한 동생이 웹페이지로부터 특정 정보를 가져오는 소스에 대해서

블로그에 적은적이 있습니다.

http://golee07.tistory.com/entry/TCPIP-Naver-Web-Parsing


간단히 말하면,

네이버에서 극장을 입력하면, 그 극장에서 상영되는 제목과 시간들을

파싱해서 나열하는 코드였는데,

정규표현식 없이 온리 C언어(소켓까지 포함)로 

약 300줄 가량 되는것을 확인하였습니다.


그래서 이런 예도 있다는걸 보여줄 겸,

perl 로 한번 다시 짜보게 되었습니다.



Windows Vim 으로 작업했고 소스는 아래와 같습니다.


총 14줄 :)



파싱이 잘 되는 것을 확인 할 수 있습니다 :)


보여주려고 짜 뒀다가 이제야 포스팅 하네요~

perl 가르쳐달라고 하는 동생의 모습이 눈에 선합니다 ^^;;



P.S.  C언어로 짜는게 나쁘다는것은 아닙니다.
     
       소켓으로 웹페이지에 접근함으로, 헤더에 어떤값이 들어간다던지 하는 부분들을 배울 수 있으며,
 
       문자열을 직접 파싱해야 됨으로 알고리즘에 대한 실력도 늘게 됩니다.

       제가 여기서 어필하고자 하는 부분은 
      
       조금더 단시간에 효율적으로 프로그램을 완성하는데 초점을 두었습니다.


신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 1 Comment 3
2010.06.16 08:41

소스 다이어트의 적절한 예


얼마전 친한 동생이 웹페이지로부터 특정 정보를 가져오는 소스에 대해서

블로그에 적은적이 있습니다.

http://golee07.tistory.com/entry/TCPIP-Naver-Web-Parsing


간단히 말하면,

네이버에서 극장을 입력하면, 그 극장에서 상영되는 제목과 시간들을

파싱해서 나열하는 코드였는데,

정규표현식 없이 온리 C언어(소켓까지 포함)로 

약 300줄 가량 되는것을 확인하였습니다.


그래서 이런 예도 있다는걸 보여줄 겸,

perl 로 한번 다시 짜보게 되었습니다.



Windows Vim 으로 작업했고 소스는 아래와 같습니다.


총 14줄 :)



파싱이 잘 되는 것을 확인 할 수 있습니다 :)


보여주려고 짜 뒀다가 이제야 포스팅 하네요~

perl 가르쳐달라고 하는 동생의 모습이 눈에 선합니다 ^^;;



P.S.  C언어로 짜는게 나쁘다는것은 아닙니다.
     
       소켓으로 웹페이지에 접근함으로, 헤더에 어떤값이 들어간다던지 하는 부분들을 배울 수 있으며,
 
       문자열을 직접 파싱해야 됨으로 알고리즘에 대한 실력도 늘게 됩니다.

       제가 여기서 어필하고자 하는 부분은 
      
       조금더 단시간에 효율적으로 프로그램을 완성하는데 초점을 두었습니다.


신고
크리에이티브 커먼즈 라이선스
Creative Commons License
Trackback 1 Comment 3


티스토리 툴바