/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;

public class IoctlWatch extends ApiHandler {
 public static final String UNKNOWN   = "UNKNOWN";

 public static final int MAXDEVNAME   = 0x20;

 public static final int IOC_WRITE    = 0x01;
 public static final int IOC_READ     = 0x02;

 public int ioc_nr(int cmd) {
  return cmd&0xff;
 }

 public int ioc_type(int cmd) {
  return (cmd>>8)&0xff;
 }

 public int ioc_size(int cmd) {
  return (cmd>>16)&0x3fff;
 }

 public int ioc_dir(int cmd) {
  return (cmd>>30)&0x03;
 }

 public String ioc_nr_name(int cmd) {
  return null;
 }

 public void ioc_dump_pre_args(int fd,int cmd,int buf) {
  String name=ioc_nr_name(cmd);

  if (name!=null) {
   ApiMonitor.log(" -> "+name);
  }

  String s="fd "+Utils.hex_value(fd,2)+" cmd "+Utils.hex_value(cmd,8)+" buf "+Utils.hex_value(buf,8);
  ApiMonitor.log(s);

  if ((ioc_dir(cmd)&IOC_WRITE)!=0) {
   int size=ioc_size(cmd);

   byte tab[]=Utils.buf2barray(buf,size);
   ApiMonitor.log_buf(tab);
  }
 }

 public void ioc_dump_post_args(int fd,int cmd,int buf,int res) {
  String name=ioc_nr_name(cmd);

  if (name!=null) {
   ApiMonitor.log(" <- "+name+" fd "+Utils.hex_value(fd,2)+" res "+Utils.hex_value(res,8));
  }

  if ((ioc_dir(cmd)&IOC_READ)!=0) {
   int size=ioc_size(cmd);

   byte tab[]=Utils.buf2barray(buf,size);
   ApiMonitor.log_buf(tab);
  } 
 }

 public IoctlWatch(String name,String function,int mid,int addr) {
  super(name,function,mid,addr);
 }

 private static String dev_from_ioctl(int fd,int cmd) {
  String dev=UNKNOWN;

  switch(cmd) {
   case 0x40194436:
   case 0x40024437:
   case 0x40284422:
   case 0x400c4435:
    dev="/dev/dmx";
    break;

   case 0x40046303:
   case 0x40046304:
    dev="/dev/sc";
    break;

   case 0xc0406f01:
    dev="/dev/vidout";
    break;

   case 0xc0086108:
    dev="/dev/avll";
    break;

   case 0xc03c640a:
   case 0xc03c640b:
   case 0xc03c6403:
   case 0xc07c6414:
    dev="/dev/vdisp";
    break;

   case 0xC0044901:
    dev="/dev/dvr0";
    break;

   case 0x00005704:
    dev="/dev/watchdog";
    break;

   case 0x4004667e:
    dev="/dev/fb";
    break;
  }

  return dev;
 }

 public void pre_ioctl(int ptr,int fd,int cmd,int buf) {
  String s=" pre   ioctl: "+" fd "+Utils.hex_value(fd,2)+" cmd "+Utils.hex_value(cmd,8)+" buf "+Utils.hex_value(buf,8);
  ApiMonitor.log(s);
 }

 public void post_ioctl(int ptr,int fd,int cmd,int buf,int res) {
 }
 
 public int pre_call(int ptr,int[] args) {     
  pre_ioctl(ptr,args[0],args[1],args[2]);
  return INVOKE_ORIGINAL;
 }

 public void post_call(int ptr,int[] args,int[] res) {
  post_ioctl(ptr,args[0],args[1],args[2],res[0]);
 }

 public static void start() {
  ApiMonitor.add("ioctl watcher","ioctl","IoctlWatch");
 }
 
}
