Ir al contenido principal

SniperlCat 0.3.1, pasado a perl estricto y correjidos bugs varios

Esta versión no trae nada nuevo, así que va a ser corto. Se pasó todo el código a perl estricto (use strict), y se corriguieron fallos tontos al interpretar las opciones de la línea de comandos, por ejemplo, si se daemonizaba después de lanzar un hilo, el hilo se cerraba por que lo hacía el proceso original =P

El trigger no cambia (bueno, en realidad cambia el notify-send, que en vez de poner 0.3, es 0.3.1, pero es estético). El código_completo_está_en_github , aunque lo importante es el Sniperlcat.pl [o_en_plano]

ps: Ya me dirán por que * no dejarán usar break; en estricto !?

Usando proxies con Python

Presento un pequeño código para usar proxies SOCKS 4 y 5 en python, en principio la idea era mostrarlo junto un servidor proxy en C, pero viendo que con esto se podía tumbar, tardará un poco más...

El código es este (para descargar completo más abajo): from socket import socket, AF_INET, SOCK_STREAM, inet_aton, getaddrinfo,\

              SOL_TCP

from string import letters

from random import choice

import sys

Lee siempre una cantidad de un socket

def sock_read(sock, n):

b = "" # Inicia el buffer

i = 0 # Tamaño del buffer

while (i < n): # Mientas no lee todo

   c = sock.recv(n - i) # Lee lo que falta



   if (len(c) < 1): # Si no se leyó nada

                    # es que el socket está cerrado

       raise Exception("Closed socket")



   b += c      # Añadir lo nuevo al buffer

   i += len(c) # y actualizar su tamaño

return b # Devolver el buffer

Convertir sockaddr a una dirección de red

def str2host(addr, ipv = 4):

for i in letters: # Si hay letras

   if i in addr[0]: # es un nombre de dominio

       d = getaddrinfo(addr[0], addr[1], 0, 0, SOL_TCP)

       # La primera dirección, el

       # primer dato de la última tupla



       for j in d:

           if (len(j[-1]) == 2) and (ipv == 4): # A ipv4 tuple

               return inet_aton(j[-1][0])

           elif (len(j[-1]) == 4) and (ipv == 6): # A ipv6 tuple

               return inet_aton(j[-1][0])

       raise Exception("Host not found")

# Sino se traduce directamente

return inet_aton(addr[0])

Pasa un número de 2 bytes a str

Suponiendo little endian

def uint16str(n):

data = [] # Prepara el buffer

data.append( chr(n & 255) ) # Lee el byte menos significativo

n >>= 8 # Mueve todo un byte a la derecha

data.append( chr(n & 255) ) # Lee el nuevo lsb

data.reverse() # Le da la vuelta (little endian)

return ''.join(data) # Y lo convierte en una cadeba

Envía el código de excepción de un servidor SOCKS4

def SOCKS4_ex(ans):

# Relación código/respuesta

s4_ex = { 91 : "Request rejected or failed",

         92 : "Request rejected becasue SOCKS server cannot connect to

identd on the client",

         93 : "Request rejected because the client program and identd

report different user-ids"}

raise Exception(s4_ex[ord(ans)]) # Produce la excepción

Envía el código de excepción de un servidor SOCKS5

def SOCKS5_ex(ans):

# Relación código/respuesta

s5_ex = { 1 : "General SOCKS server failure",

         2 : "Connection not allowed by ruleset",

         3 : "Network unreachable",

         4 : "Host unreachable",

         5 : "Connection refused",

         6 : "TTL expired",

         7 : "Command not supported",

         8 : "Address type not supported" }

raise Exception(s5_ex[ord(ans)]) # Produce la excepción

Especifica la dirección a un proxy SOCKS

def SOCKS_hop(sock, addr, proto = 4, ipv = 4):

if (proto == 4): # Protocolo SOCKS4

   # Mensaje de conexión

   sock.send(chr(4) + chr(1) + uint16str(addr[1]) + str2host(addr) +\

        chr(0))



   # Mensaje de confirmación/error

   code = sock_read(sock, 8)[1]



   # Si algo falló

   if (code != chr(90)):

       # Mandar una excepción

       SOCKS4_ex(code)

elif (proto == 5): # Protocolo SOCKS5

   atype = None

   if (ipv == 4): # Hosts ipv4

       atype = chr(1)

   elif (ipv == 6): # Hosts ipv6

       atype = chr(4)

   else:

       raise Exception("Unknown IP version")



   sock.send(chr(5) + chr(1) + chr(0))



   # Mensaje de confirmación/error

   code = sock_read(sock, 2)



   if (code != (chr(5) + chr(0))):

       raise Exception("Requiere autenticación")



   # Mensaje de conexión

   l = sock.send(chr(5) + chr(1) + chr(0) + atype + str(str2host(addr)) +\

        uint16str(addr[1]))



   # Mensaje de confirmación/error

   code = sock_read(sock, l)[1]



   # Si algo falló

   if (code != chr(00)):

       # Mandar una excepción

       SOCKS5_ex(code)

else: # Protocolo desconocido

   raise Exception("Unknown SOCKS version")

Simplemente hay que levantar una conexión hacia un proxy y luego llamar a SOCKS_hopcon los siguientes argumentos:

* El socket que se uso para la conexión

* Una tupla dirección/puerto como al conectar un socket

* Versión de SOCKS: 4 o 5(Opcional, por defecto 4)

* Versión del protocolo IP (Opcional, por defecto 4)
*

Si se produce un error en el proceso (no está conectado a un servidor SOCKS o le servidor no se pudo conectar al nuevo host, por ejemplo) manda una excepción.

Para este ejemplo, si se pasa algún parámetro, se leerá como una lista de proxies (ip:puerto   en cada línea) y va saltando entre proxies al azar. Sino se le pasa ningún parámetro se conecta a localhost en el puerto 1080 y intenta usarlo como servidor SOCKS5 para ver cuantas veces se puede conectar a si mismo [Cuidado]: unos cuantos hilos haciendo esto provocaron algo parecido a un DOS en un pequeño servidor SSH funcionando como proxy =P if name == "main":

if (len(sys.argv) > 1):

   plist = []

   f = open(sys.argv[1], "rt")

   while True:

       txt = f.readline()

       if (len(txt) < 1):

           break

       addr = txt.split(":")

       plist.append((addr[0], int(addr[1])))



   f.close()





   last = choice(plist)  # Selecciona un proxy al azar

   next = last

   i = 0



   sys.stdout.write("[" + str(i) + "] " + str(next))

   sys.stdout.flush()

   sock = socket(AF_INET, SOCK_STREAM)

   sock.connect(next)

   sys.stdout.write("\n")

   while True:

       i += 1

       while (next == last):

           next = choice(plist)

       last = next

       sys.stdout.write("[" + str(i) + "] " + str(next))

       sys.stdout.flush()

       SOCKS_hop(sock, next)

       sys.stdout.write("\n")

else:

   sock = socket(AF_INET, SOCK_STREAM)



   #sock.connect(('127.0.0.1', 4444))

   sock.connect(('localhost', 1080))

   i = 0

   while True:

       #SOCKS_hop(sock, ('localhost', 4444))

       SOCKS_hop(sock, ('127.0.0.1', 1080), 5)

       i += 1

       print i

El código completo [pysocks.py] [Referencias] SOCKS_4 SOCKS_4A RFC1928_-_SOCKS5

Proceso de escritura de un shellcode

Hoy me ha entrado del vicio de escribir un shellcode, aquí queda el proceso para quien se pregunte como se escriben estos extraños seres de la fauna binaria.

Actualización: me había olvidado del BITS 32 en el shellcode para que funcione bien

Un shellcode, llamados así porque generalmente lo que hacían era presentar una shell (aunque se puede hacer cualquier cosa con ellos), son trozos de código ensamblador, normalmente pasados a formato hexadecimal para un "consumo" más cómodo, cuya característica más importante es que se pueden cargar en cualquier posición de memoria.

Empezamos escribiendo un código que llame a execl con /bin/bash como parámetro[ http://pastebin.com/8FTgE4yz ]:

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

section .data ; Datos comando: db '/bin/bash', 0 nullstring: dd 0

section .text ; Código global _start

_start: ; Inicio mov eax, 11 ; execve mov ebx, comando ; path del ejecutable mov ecx, nullstring ; un 0, no se usarán parámetros

int 0x80     ; Joeeeeeeeee!!! una de kerneeeeeeeel !!!

_end:   ; Esto solo lo finaliza mov eax, 1 ; sys_exit mov ebx, 0

int 0x80

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

Lo siguiente es eliminar las direcciones absolutas lo que incluye todo el section .data, así que usaremos el stack para eso, recordar que crece hacia abajo, hay que meter las cosas "al revés"

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

section .text ; Código global _start

_start: ; Inicio push dword 0

mov ecx, esp ; Se guarda esta posición del stack ; servirá para los argumentes

; //bin/bash , para cuadrarlo en words push dword 0x68736162 ; hsab (bash) push dword 0x2f6e6962 ; /nib (bin/) push word  0x2f2f     ; //

mov eax, 11 ; execve mov ebx, esp ; path del ejecutable int 0x80     ; Se llama al kernel

_end:   ; Esto solo lo finaliza mov eax, 1 ; sys_exit mov ebx, 0 int 0x80

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

Queda eliminar los 0's del código, ya que desensamblado es así

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

00000000  680000            push word 0x0 00000003  0000              add  [bx+si],al 00000005  89E1              mov cx,sp 00000007  686261            push word 0x6162 0000000A  7368              jnc 0x74 0000000C  686269            push word 0x6962 0000000F  6E                outsb 00000010  2F                das 00000011  66682F2FB80B      push dword 0xbb82f2f 00000017  0000              add  [bx+si],al 00000019  0089E3CD          add [bx+di- 0x321d],cl 0000001D  80B8010000        cmp byte  [bx+si+0x1],0x0 00000022  00BB0000          add  [bp+di+0x0],bh 00000026  0000              add  [bx+si],al 00000028  CD80              int 0x80

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

Y un shellcode con bytes nulos no es todo lo útil que podría, aquí los XOR allanan el camino

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

BITS 32

section .text ; Código global _start

_start: ; Inicio xor eax, eax

push eax

mov ecx, esp ; Se guarda esta posición del stack ; servirá para los argumentes

; ////bin/bash , para cuadrarlo en words push dword 0x68736162 ; hsab (bash) push dword 0x2f6e6962 ; /nib (bin/)

push word  0x2f2f     ; //

mov al, 11 ; execve

mov ebx, esp ; path del ejecutable

int 0x80

_end:   ; Esto solo lo finaliza xor eax, eax ; sys_exit xor ebx, ebx

inc eax int 0x80

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

Desensamblado:

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

00000000  31C0              xor ax,ax 00000002  50                push ax 00000003  89E1              mov cx,sp 00000005  686261            push word 0x6162 00000008  7368              jnc 0x72 0000000A  686269            push word 0x6962 0000000D  6E                outsb 0000000E  2F                das 0000000F  66682F2FB00B      push dword 0xbb02f2f 00000015  89E3              mov bx,sp 00000017  CD80              int 0x80 00000019  31C0              xor ax,ax 0000001B  31DB              xor bx,bx 0000001D  40                inc ax 0000001E  CD80              int 0x80

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

Sin ningún NULO, listo para servir

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

\x31\xc0\x50\x89\xe1\x68\x62\x61\x73\x68\x68\x62\x69\x6e\x2f\x66\x68\x2f\x2f\xb0\x0b\x89\xe3\xcd\x80\x31\xc0\x31\xdb\x40\xcd\x80

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

ps: para quién llegó hasta aquí hay premio xD, un script para pasar el dumpeo binario de un shellcode al formato de string que se suele utilizar [ http://pastebin.com/mubdwfXS ]

Que aproveche :D!

Intérprete de Redcode

[Link corregido]

Hoy traigo un pequeño intérprete de Redcode (si, el lenguaje del Corewars). Tiene sus limitaciónes (digamos que sigue las primeras versiones del lenguaje), por ejemplo, no tiene p-space ni modificadores (instrucción.Modificador) a excepcion de STS, que muestra un carácter por pantalla, y LDS que obtiene un carácter de STDIN (instrucciones que no se usan en el juego ), para más referencias [ Redcode_-_Esolang ].

Obviamente la idea al programar esto fue intentar comprender un poco más como funcionan los intérpretes y compiladores.

Centrandose en el programa en sí, (se puede descargar aquí [redcode01.tar.gz]), lo único que hay que hacer es make para compilarlo, y

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

./redcode

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

para intérpretar un código.Además decir que ignora las líneas con un '#' al principio, para permitir que el intérprete se lance con un #!.

Hay más formas de usarlo, se pueden ver con

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

kenkeiras@viaxante:~/%%%%%$ ./redcode Uso: ./redcode [--help |--compile | --decompile | --load-compiled] [--verbose] [--mem-length=] --help: Muestra esto - Shows this --compile: Compila el bytecode y lo muestra por STDOUT - Compiles the bytecode and shows it throught STDOUT --decompile: Decompila el bytecode - Decompiles the bytecode --load-compiled: Ejecuta un bytecode - Executes a bytecode --verbose: Muestra información para el debugging - Shows debugging info --mem-length: Ajusta la longitud de la memoria - Set's the mem length

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

Creo que es bastante auto explicativo.

La parte de compilar y cargar directamente despues está para evitar el procesamiento extra del parser (esto para Redcode no tiene mucho sentido, pero para otros lenguajes podria tenerlo,y recordemos que la idea era aprender =) ).

Por último, algunos programas utilizados para probarlo...

ps: Perdón desde ya por el surfing de punteros :S.

El hola mundo (no puede faltar :D) [http://pastebin.com/cbtGkj5F]:

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

; Redcode Hello World, John Metcalf

write   sts.a  hello,     0 sts.b  }write,    0 djn    write,     #7

hello   dat    72,        101 ; He dat    108,       108 ; ll dat    111,       44  ; o, dat    32,        87  ;  W dat    111,       114 ; or dat    108,       100 ; ld dat    33,        10  ; !\n

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

Adaptado para usar SPL (varios procesos)[http://pastebin.com/rqrugthE]:

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

; Redcode multiprocess Hello World ; Original by John Metcalf ; Modified by kenkeiras (Added parallel functions)

spl fork write   sts.a  hello, 0 djn    -1, #7

hello   dat    72,        101 ; He dat    108,       108 ; ll dat    111,       44  ; o, dat    32,        87  ;  W dat    111,       114 ; or dat    108,       100 ; ld dat    33,        10  ; !\n

fork    sts.b  }write, 0 djn    -1, #7

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

Un imp (simple pero eficaz para probar los extremos de la memoria):

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

mov    0, 1

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

Y uno que se copia seguido hacia atras[http://pastebin.com/x8qNf15b]:

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

;name Backrunner ;author Kenkeiras

SUB #7,inst    ;Para reajustar el puntero de instruccion SUB #6,pos     ; " MOV >inst,>pos SEQ inst,check JMP -2

JMP -14 ;Al proximo paso

pos   DAT #-9 inst  DAT #0 ;Los valores que quedaran despues de copiarse a si mismos check DAT #2

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

Hasta otra.

[Referencias] http://impomatic.blogspot.com/ Redcode_-_Esolang

Probando scratch

"Scratch es un lenguaje de programación que hace fácil crear tus
propias historias interactivas, animaciones, juegos, musica y arte -
- y compartir tus creaciones en la red.
Cuando la gente joven crea y comparte proyectos de Scratch, aprenden
importantes ideas sobre las matemáticas y la computación, mientras
aprenden también a pensar de forma creativa, razonar
systematicamente y trabajar colaborativamente."

Eso es lo que dicen de este proyecto en_su_web, solo cabría añadir que fue desarrollado en el MIT y que el código está basado en "bloques" de instrucciones, no en texto, haciendolo muy visual y evitando errores sintácticos.

Obviamente no es un lenguaje pensado para la programación en general aunque permita muchas cosas de ella: variables, condiciones, bucles, operaciones...  La interfaz es bastante simple y autoexplicativa, tanto que para programar solo hace falta saber leer, hasta los bloques de código están traducidos a varios idiomas:  [http://videobin.org/+2bu/2me.html]

El programa se puede descargar de aquí http://info.scratch.mit.edu/ Scratch_1.4_Download , los que usen una distro con apt-get pueden añadir directamente el repositorio

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

deb http://ppa.launchpad.net/scratch/ppa/ubuntu main

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

La versión de la distro debería ser la más "equivalente" posible a la versión de ubuntu (para Trisquel Taranis, por ejemplo, sería lucid)

Algo que me parecio curioso es que soporta gráficos de tortuga, como el lenguaje logo, por ejemplo, este 'código':

Genera esta figura:

También permite interactuar fácilmente con el usuario, por ejemplo, este utiliza el lápiz de los gráficos de tortuga para 'perseguir' al ratón:

Como se puede ver, el lenguaje es muy intuitivo y no hay que andar por medio internet buscando como hacer tal o cual cosa, el propio programa provee los bloques con las instrucciones, solo hay que moverlos hasta donde se quieran poner y listo :D.

Eso es todo, nos vemos.

Un autómata celular para generar números pseudo-aleatorios

La idea no es la primera vez que se oye, creo que fue_Wolfram_quién_lo_propuso en_su_momento, pero el concepto no deja de ser curioso, y el otro día trasteando con Golly me encontre con que una pequeña variante del juego_de_la vida_de_Conway, con la diferencia de que una "célula" también puede "nacer" si tiene 4 vecinos (y no solo 3) llamado "3-4 life", que hace que patrones sencillos crezcan indefinidamente quedando el contenido en su interior algo aleatorio, esta es una simulación de las 250 primeras generaciones [http:// videobin.org/+2be/2ly.html].

Lo que intenta hacer el código es expandir la figura inicial estas 250 generaciones e introducir una "semilla de aleatoriedad", que puede ser un string cualquiera o se puede leer de un archivo, lo que hará que la figura crezca de forma distinta cada vez. Se deja además 1000 generaciones para que esta semilla se mezcle bien, y el resultado se utiliza para generar números pseudo-aleatorios, que no creo que sean criptográficamente.

Una peculiaridad es que el campo es de 40x40 (pero esto se puede cambiar) y toroidal, es decir, cuando la primera fila comprueba lo que tendría encima, se leen las de la última, y vieceversa, lo mismo pasa con  derecha e izquierda.

El código está aquí [autorand.tar.gz], solo hay que compilar autorand.c directamente.

Por defecto la "semilla de aleatoriedad" se lee desde el teclado, esto se puede cambiar al lanzar el comando:

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

./autorand [-fs ] [-s ] [-ss ] [-sz ] [-bs] [-st ] [-mo ] [-h] -fs: Tamaño del campo (anchura/altura) -s: Semilla de aleatoriedad -ss: Fuente de la semilla -sz: Tamaño de la semilla -bs: La semilla se lee como un archivo binario no se detiene al encontrar saltos de línea -st: Tipo de la semilla del campo (0 o 1) -mo: Tamaño de la semilla

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

Eso es todo por hoy, mañana más... y dificilmente peor =D

SniperlCat 0.3, suma y sigue

Pues nada, nueva versión de sniperlcat, los cambios son: - Los avisos los hace un script a parte, eliminando GTK de las dependencias y haciendo que no haya que trastear en el código para que haga algo distinto con los avisos. - Corregido al bug que lo volvia paranoico al cerrar el dispositivo...al final solo había que reabrirlo =) - Añadida la opción de poner a la escucha un puerto cualquiera para detectar los scanners que se conectan a el, si se utiliza varias veces se escuchan varios puertos (cada uno en un hilo distinto).

La opción de escuchar puertos se añadió por la necesidad de detectar scanners de conexión, (y de evitar tener que ser root para detectar los escaneos), que además se pueda elegir el mensaje que envía es para hacerse pasar por un servicio legítimo, por ejemplo, "SSH-2.0-OpenSSH_5.3p1 Debian- 3ubuntu4" hace que amap lo marque como un servidor openssh =D

Los cambios están subidos a github [http://github.com/kenkeiras/Sniperlcat], también se pueden descargar los dos archivos por separado [sniperlcat.pl] y [trigger.sh].

La sintaxis del comando queda así, entonces (todo es retrocompatible)

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

Sniperlcat 0.3 sniperlcat [-h]|[-d | -v ] [-nf] [-c] [-n ] [-f ] [-p|- np] [-dv ] [-l ] [-s ] [-t ] [-p ] -h (--help): Muestra este mensaje -d (--daemonize): Se ejecuta de fondo -nf (--no-fill): No llena la tabla de hosts (con nmap) antes de leerla -c (--cansino): Repite los avisos, aún los ya emitidos, en cada iteración -v (--verbose): Muestra más información por pantalla -n (--network): Especifica la red donde se ejecuta, por defecto 192.168.1.0/24 -dv (--device): Especifica la interfaz de red que se monitoreará -p (--privileged): Se asumirán que es un usuario con privilegios -np (--no-privileged): Se asumirán que es un usuario sin privilegios -l (--log): Se guardarán los avisos en un archivo -s (--sleep): Especifica el tiempo en segundos de "descanso" entre iteraciones (por defecto 60) -t (--trigger) Especifica el trigger que se disparará en las alertas -pt (--port): Especifica un puerto para esperar conexiones y el mensaje que envia

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

Eso es todo, hasta otra.

Invertir los canales de sonido

Otro script más que engrosa las listas de lo programado solo por programar [http://pastebin.com/FzQmDxKP].

Recibe como parámetros el archivo original y el nombre del que se creará y copia el sonido del primero en el segundo cambiando el canal de la derecha por el de la izquierda y viceversa.

Meh... pues si que quedo pequeño el post =P.

Como generar una onda de Audio para archivos WAV (PCM)

Como en su momento no encontré nada sobre este tema, aquí va una pequeña explicación de como generar audio modulado en PCM, lo que usa por ejemplo, el formato WAV.

Partiremos de algunos conceptos básicos que supongo que conoceréis:

Sobre las ondas de sonido:

* Frecuencia de la onda: veces en un segundo que la onda se repite (o que
pasa por el valor intermedio).

* Amplitud de la onda: en este caso, la distancia entre el punto más alto
y el más bajo, determinará el volumen.
*

Sobre su representación en el archivo:

* Framerate: número de veces por segundo que se representa la onda (a más
framerate, más cercano es a la onda original y mejor calidad).

* Canales: número de salidas del audio (1: Mono, 2: Stereo).
*
* Ancho de canal: bits que se dedican a cada frame de cada canal (suele ser
de 16 bits).
*

Para la manipulación de los archivos WAV se puede usar la librería_estándar de_python_wave, haciendo que el manejo del archivo sea muy simple, por lo que me centraré en la generación de la onda, que es lo que no implementa.

Supongamos, por ejemplo, que queremos generar una onda de 300Hz que dure 1 segundo, lo primero es generar una onda completa que nos servirá de base:

  • Si la frecuencia es cero, la onda es plana, así que se representaría como un solo valor, 0

Sino, tendremos para generar una onda completa, para ello se necesitan tantos frames como framerate/frecuencia, para que la onda esté completa, además, como la onda es sinusoidal, tomará valores de seno de entre 0 y 2 PI , así que por último hay que partir de la base b = (2 * pi) / frames y  multiplicarlo por cada frame, el código de esta parte quedaría así:

import math

def getBase(freq, framerate):

# Si no es una onda plana

if (freq != 0):

   base = []



   # Se obtiene el numero de frames a generar

   frames = int(framerate / abs(freq))



   # Y la base de los valores que tomaran

   p = (math.pi * 2) / frames



   # Por ultimo se genera la onda sinusoidal entre seno de  0 y 2*Pi

   for i in xrange(frames):

       base.append(math.sin(i * p))

# Si es una onda plana

else:

   base = [0]

return base

El siguiente paso es añadir a la onda base el volumen y los canales, para añadir el volumen simplemente hay que multiplicar el valor de un frame por el volumen, el valor del volumen (usando PCM con signo, como en WAV) puede variar entre 0 y 2**(ancho de banda - 1) - 1, para 8 bits sería entre 0 y 127, y para 16 bits, entre 0 y 32767. Por ultimo, solo hay que repetir el frame por cada canal (aunque si va a ser la misma onda no hay motivos para usar múltiples canales...)

Fija el volumen y los canales

def setVolChan(src, vol, n_can):

out = []

for i in src:

   n = int(i * vol) # Se aplica el volumen

   out.append([n] * n_can) # Y se replica para otros canales

return out

A continuación hay que extender la onda para todo el tiempo que cubra

Extiende la base a todo el tiempo

def mkFrames(base, t, framerate):

   base_flen = len(base) / float(framerate) # Lo que dura la base



   n = int(round(t / base_flen)) # Las veces que hay que repetirla



   return base * n

Y solo queda convertir la onda a una cadena (es el formato que utiliza la librería wave), si los canales fueran de 8 bits se podría usar una funcion de array directamente:

cadena = array.array('b', original).tostring()

Sino, hay que hacerlo a mano

def arr2Stream(sample, width):

stream = ""

for i in sample: # Por cada frame

   for k in i:  # Y cada canal

       for j in xrange(width):

           stream += chr(k & 255 ) # Se extrae un byte

           k >>= 8

return stream

Un código completo sería (los cambios se hacen en las variables al principio del codigo), entonces [audio_sample.py]:

!/usr/bin/env python

canales = 2 # Stereo

framerate = 11025

ancho = 16

volumen = 10000 # Para un ancho de canal de 16 bits

frecuencia = 300 # Hz

duracion = 2 # Segundos

archivo = "salida.wav"

def arr2Stream(sample, width):

stream = ""

for i in sample: # Por cada frame

   for k in i:  # Y cada canal

       for j in xrange(width):

           stream += chr(k & 255 ) # Se extrae un byte

           k >>= 8

return stream

def getBase(freq, framerate):

# Si no es una onda plana

if (freq != 0):

   base = []



   # Se obtiene el numero de frames a generar

   frames = int(framerate / abs(freq))



   # Y la base de los valores que tomaran

   p = (math.pi * 2) / frames



   # Por ultimo se genera la onda sinusoidal entre seno de  0 y 2*Pi

   for i in xrange(frames):

       base.append(math.sin(i * p))

# Si es una onda plana

else:

   base = [0]

return base

Fija el volumen y los canales

def setVolChan(src, vol, n_can):

out = []

for i in src:

   n = int(i * vol) # Se aplica el volumen

   out.append([n] * n_can) # Y se replica para otros canales

return out

Extiende la base a todo el tiempo

def mkFrames(base, t, framerate):

   base_flen = len(base) / float(framerate) # Lo que dura la base



   n = int(round(t / base_flen)) # Las veces que hay que repetirla



   return base * n

def genFrames(freq, t, framerate, vol, chan, width):

   s = getBase(freq, framerate)

   s = setVolChan(s, vol, chan)

   s = mkFrames( s, t, framerate)

   return arr2Stream(s, width)

import math, wave

w = wave.open(archivo, "wb")

w.setnchannels(canales)

w.setsampwidth(ancho / 8)

w.setframerate(framerate)

w.writeframes(genFrames(frecuencia, duracion, framerate, volumen, canales, ancho / 8))

w.close()

Ve con root =)

[Offtopic] Thunderbird te avisa si te olvidas de adjuntar algo

Parece que thunderbird añadió la característica de avisar al usuario de que falta algo por adjuntar si observa algo en el mensaje que indica que se debería haber hecho (algo como nombrar un tipo de archivo común)

[http://1.bp.blogspot.com/_26RJWnubh-w/TMboUfMRFrI/AAAAAAAAARk/YaUd_xhHL0o/ s320/thunder.png]                [Recordatorio de Adjunto] ¿Te olvidaste de añadir un adjunto? [X ¡Oh, me olvide!] [✓ No, enviar ahora]

Btw, si a alguién le falla el programa para capturar la pantalla puede probar con: =============================================================================== sleep 1;import -frame salida.png ===============================================================================

Se puede cambiar el 1 de sleep por el tiempo que se esperará antes de sacar la foto, y salida.png por el nombre del archivo de salida, solo hay que lanzarlo y cuando el cursor cambie, hacer click sobre la ventana que se quiere capturar. Se puede eliminar el -frame para no capturar la barra superior de la ventana.

Saludos